summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Android.mk2
-rw-r--r--Docs.mk11
-rw-r--r--JavaLibrary.mk68
-rw-r--r--NOTICE11
-rw-r--r--NativeCode.mk54
-rw-r--r--benchmarks/Android.mk2
-rw-r--r--benchmarks/src/benchmarks/regression/BreakIteratorBenchmark.java72
-rw-r--r--benchmarks/src/benchmarks/regression/CollectionsBenchmark.java80
-rw-r--r--benchmarks/src/benchmarks/regression/DateIntervalFormatBenchmark.java20
-rw-r--r--benchmarks/src/benchmarks/regression/ProviderBenchmark.java50
-rw-r--r--benchmarks/src/benchmarks/regression/ReflectionBenchmark.java7
-rw-r--r--benchmarks/src/benchmarks/regression/RelativeDateTimeFormatterBenchmark.java68
-rw-r--r--dalvik/src/main/java/dalvik/system/BaseDexClassLoader.java1
-rw-r--r--dalvik/src/main/java/dalvik/system/CloseGuard.java8
-rw-r--r--dalvik/src/main/java/dalvik/system/DexFile.java59
-rw-r--r--dalvik/src/main/java/dalvik/system/DexPathList.java194
-rw-r--r--dalvik/src/main/java/dalvik/system/StaleDexCacheError.java41
-rw-r--r--dalvik/src/main/java/dalvik/system/VMDebug.java55
-rw-r--r--dalvik/src/main/java/dalvik/system/ZygoteHooks.java13
-rw-r--r--expectations/brokentests.txt6
-rw-r--r--expectations/knownfailures.txt94
-rw-r--r--expectations/taggedtests.txt1
-rw-r--r--harmony-tests/src/test/java/org/apache/harmony/tests/java/io/FileTest.java4
-rw-r--r--harmony-tests/src/test/java/org/apache/harmony/tests/java/lang/ProcessTest.java11
-rw-r--r--harmony-tests/src/test/java/org/apache/harmony/tests/java/lang/ref/ReferenceQueueTest.java17
-rw-r--r--harmony-tests/src/test/java/org/apache/harmony/tests/java/net/DatagramSocketTest.java13
-rw-r--r--harmony-tests/src/test/java/org/apache/harmony/tests/java/net/InetAddressTest.java2
-rw-r--r--harmony-tests/src/test/java/org/apache/harmony/tests/java/net/MulticastSocketTest.java5
-rw-r--r--harmony-tests/src/test/java/org/apache/harmony/tests/java/nio/DirectByteBufferTest.java57
-rw-r--r--harmony-tests/src/test/java/org/apache/harmony/tests/java/nio/charset/CharsetTest.java110
-rw-r--r--harmony-tests/src/test/java/org/apache/harmony/tests/java/text/ChoiceFormatTest.java20
-rw-r--r--harmony-tests/src/test/java/org/apache/harmony/tests/java/text/MessageFormatTest.java8
-rw-r--r--harmony-tests/src/test/java/org/apache/harmony/tests/java/util/CurrencyTest.java4
-rw-r--r--harmony-tests/src/test/java/org/apache/harmony/tests/java/util/EnumMapTest.java11
-rw-r--r--harmony-tests/src/test/java/org/apache/harmony/tests/javax/net/ServerSocketFactoryTest.java2
-rw-r--r--harmony-tests/src/test/java/org/apache/harmony/tests/javax/net/SocketFactoryTest.java2
-rw-r--r--harmony-tests/src/test/java/org/apache/harmony/tests/javax/net/ssl/CertPathTrustManagerParametersTest.java2
-rw-r--r--harmony-tests/src/test/java/org/apache/harmony/tests/javax/net/ssl/CertificatesToPlayWith.java2
-rw-r--r--harmony-tests/src/test/java/org/apache/harmony/tests/javax/net/ssl/HandshakeCompletedEventTest.java2
-rw-r--r--harmony-tests/src/test/java/org/apache/harmony/tests/javax/net/ssl/HostnameVerifierTest.java8
-rw-r--r--harmony-tests/src/test/java/org/apache/harmony/tests/javax/net/ssl/HttpsURLConnectionTest.java2
-rw-r--r--harmony-tests/src/test/java/org/apache/harmony/tests/javax/net/ssl/KeyManagerFactory1Test.java2
-rw-r--r--harmony-tests/src/test/java/org/apache/harmony/tests/javax/net/ssl/KeyManagerFactory2Test.java2
-rw-r--r--harmony-tests/src/test/java/org/apache/harmony/tests/javax/net/ssl/KeyManagerFactorySpiTest.java2
-rw-r--r--harmony-tests/src/test/java/org/apache/harmony/tests/javax/net/ssl/KeyStoreBuilderParametersTest.java2
-rw-r--r--harmony-tests/src/test/java/org/apache/harmony/tests/javax/net/ssl/SSLContext1Test.java2
-rw-r--r--harmony-tests/src/test/java/org/apache/harmony/tests/javax/net/ssl/SSLContext2Test.java2
-rw-r--r--harmony-tests/src/test/java/org/apache/harmony/tests/javax/net/ssl/SSLContextSpiTest.java2
-rw-r--r--harmony-tests/src/test/java/org/apache/harmony/tests/javax/net/ssl/SSLEngineResultHandshakeStatusTest.java2
-rw-r--r--harmony-tests/src/test/java/org/apache/harmony/tests/javax/net/ssl/SSLEngineResultStatusTest.java2
-rw-r--r--harmony-tests/src/test/java/org/apache/harmony/tests/javax/net/ssl/SSLEngineResultTest.java2
-rw-r--r--harmony-tests/src/test/java/org/apache/harmony/tests/javax/net/ssl/SSLEngineTest.java23
-rw-r--r--harmony-tests/src/test/java/org/apache/harmony/tests/javax/net/ssl/SSLExceptionTest.java2
-rw-r--r--harmony-tests/src/test/java/org/apache/harmony/tests/javax/net/ssl/SSLHandshakeExceptionTest.java2
-rw-r--r--harmony-tests/src/test/java/org/apache/harmony/tests/javax/net/ssl/SSLKeyExceptionTest.java2
-rw-r--r--harmony-tests/src/test/java/org/apache/harmony/tests/javax/net/ssl/SSLPeerUnverifiedExceptionTest.java2
-rw-r--r--harmony-tests/src/test/java/org/apache/harmony/tests/javax/net/ssl/SSLProtocolExceptionTest.java2
-rw-r--r--harmony-tests/src/test/java/org/apache/harmony/tests/javax/net/ssl/SSLServerSocketFactoryTest.java2
-rw-r--r--harmony-tests/src/test/java/org/apache/harmony/tests/javax/net/ssl/SSLServerSocketTest.java2
-rw-r--r--harmony-tests/src/test/java/org/apache/harmony/tests/javax/net/ssl/SSLSessionBindingEventTest.java2
-rw-r--r--harmony-tests/src/test/java/org/apache/harmony/tests/javax/net/ssl/SSLSessionBindingListenerTest.java2
-rw-r--r--harmony-tests/src/test/java/org/apache/harmony/tests/javax/net/ssl/SSLSessionContextTest.java2
-rw-r--r--harmony-tests/src/test/java/org/apache/harmony/tests/javax/net/ssl/SSLSessionTest.java6
-rw-r--r--harmony-tests/src/test/java/org/apache/harmony/tests/javax/net/ssl/SSLSocketFactoryTest.java2
-rw-r--r--harmony-tests/src/test/java/org/apache/harmony/tests/javax/net/ssl/SSLSocketTest.java4
-rw-r--r--harmony-tests/src/test/java/org/apache/harmony/tests/javax/net/ssl/TrustManagerFactory1Test.java2
-rw-r--r--harmony-tests/src/test/java/org/apache/harmony/tests/javax/net/ssl/TrustManagerFactory2Test.java2
-rw-r--r--harmony-tests/src/test/java/org/apache/harmony/tests/javax/net/ssl/TrustManagerFactorySpiTest.java2
-rw-r--r--harmony-tests/src/test/java/org/apache/harmony/tests/javax/net/ssl/X509ExtendedKeyManagerTest.java2
-rw-r--r--harmony-tests/src/test/java/org/apache/harmony/tests/javax/net/ssl/X509KeyManagerTest.java2
-rw-r--r--harmony-tests/src/test/java/org/apache/harmony/tests/javax/net/ssl/X509TrustManagerTest.java2
-rw-r--r--harmony-tests/src/test/java/org/apache/harmony/tests/javax/security/cert/X509CertificateTest.java15
-rw-r--r--harmony-tests/src/test/resources/META-INF/services/java.nio.charset.spi.CharsetProvider2
-rw-r--r--include/ScopedIcuLocale.h6
-rw-r--r--include/ScopedJavaUnicodeString.h6
-rw-r--r--jarjar-rules.txt1
-rw-r--r--json/src/main/java/org/json/JSONTokener.java11
-rw-r--r--json/src/test/java/org/json/JSONObjectTest.java9
-rw-r--r--json/src/test/java/org/json/JSONTokenerTest.java5
-rw-r--r--jsr166-tests/src/test/java/jsr166/AbstractExecutorServiceTest.java43
-rw-r--r--jsr166-tests/src/test/java/jsr166/AbstractQueueTest.java37
-rw-r--r--jsr166-tests/src/test/java/jsr166/AbstractQueuedLongSynchronizerTest.java51
-rw-r--r--jsr166-tests/src/test/java/jsr166/AbstractQueuedSynchronizerTest.java49
-rw-r--r--jsr166-tests/src/test/java/jsr166/ArrayBlockingQueueNonFairTest.java (renamed from jsr166-tests/src/test/java/jsr166/ArrayBlockingQueueNotFairTest.java)2
-rw-r--r--jsr166-tests/src/test/java/jsr166/ArrayBlockingQueueTest.java118
-rw-r--r--jsr166-tests/src/test/java/jsr166/ArrayDequeTest.java66
-rw-r--r--jsr166-tests/src/test/java/jsr166/AtomicBooleanTest.java19
-rw-r--r--jsr166-tests/src/test/java/jsr166/AtomicIntegerArrayTest.java28
-rw-r--r--jsr166-tests/src/test/java/jsr166/AtomicIntegerFieldUpdaterTest.java19
-rw-r--r--jsr166-tests/src/test/java/jsr166/AtomicIntegerTest.java19
-rw-r--r--jsr166-tests/src/test/java/jsr166/AtomicLongArrayTest.java28
-rw-r--r--jsr166-tests/src/test/java/jsr166/AtomicLongFieldUpdaterTest.java20
-rw-r--r--jsr166-tests/src/test/java/jsr166/AtomicLongTest.java19
-rw-r--r--jsr166-tests/src/test/java/jsr166/AtomicMarkableReferenceTest.java17
-rw-r--r--jsr166-tests/src/test/java/jsr166/AtomicReferenceArrayTest.java21
-rw-r--r--jsr166-tests/src/test/java/jsr166/AtomicReferenceFieldUpdaterTest.java32
-rw-r--r--jsr166-tests/src/test/java/jsr166/AtomicReferenceTest.java19
-rw-r--r--jsr166-tests/src/test/java/jsr166/AtomicStampedReferenceTest.java17
-rw-r--r--jsr166-tests/src/test/java/jsr166/BlockingQueueTest.java20
-rw-r--r--jsr166-tests/src/test/java/jsr166/ConcurrentHashMapTest.java239
-rw-r--r--jsr166-tests/src/test/java/jsr166/ConcurrentLinkedDequeTest.java79
-rw-r--r--jsr166-tests/src/test/java/jsr166/ConcurrentLinkedQueueTest.java56
-rw-r--r--jsr166-tests/src/test/java/jsr166/ConcurrentSkipListMapTest.java51
-rw-r--r--jsr166-tests/src/test/java/jsr166/ConcurrentSkipListSetTest.java72
-rw-r--r--jsr166-tests/src/test/java/jsr166/ConcurrentSkipListSubMapTest.java22
-rw-r--r--jsr166-tests/src/test/java/jsr166/ConcurrentSkipListSubSetTest.java92
-rw-r--r--jsr166-tests/src/test/java/jsr166/CopyOnWriteArrayListTest.java280
-rw-r--r--jsr166-tests/src/test/java/jsr166/CopyOnWriteArraySetTest.java102
-rw-r--r--jsr166-tests/src/test/java/jsr166/CountDownLatchTest.java17
-rw-r--r--jsr166-tests/src/test/java/jsr166/CountedCompleterTest.java42
-rw-r--r--jsr166-tests/src/test/java/jsr166/CyclicBarrierTest.java17
-rw-r--r--jsr166-tests/src/test/java/jsr166/DelayQueueTest.java106
-rw-r--r--jsr166-tests/src/test/java/jsr166/EntryTest.java16
-rw-r--r--jsr166-tests/src/test/java/jsr166/ExchangerTest.java18
-rw-r--r--jsr166-tests/src/test/java/jsr166/ExecutorCompletionServiceTest.java24
-rw-r--r--jsr166-tests/src/test/java/jsr166/ExecutorsTest.java37
-rw-r--r--jsr166-tests/src/test/java/jsr166/ForkJoinPoolTest.java47
-rw-r--r--jsr166-tests/src/test/java/jsr166/ForkJoinTaskTest.java46
-rw-r--r--jsr166-tests/src/test/java/jsr166/FutureTaskTest.java57
-rw-r--r--jsr166-tests/src/test/java/jsr166/JSR166TestCase.java202
-rw-r--r--jsr166-tests/src/test/java/jsr166/LinkedBlockingDequeTest.java120
-rw-r--r--jsr166-tests/src/test/java/jsr166/LinkedBlockingQueueTest.java91
-rw-r--r--jsr166-tests/src/test/java/jsr166/LinkedListTest.java45
-rw-r--r--jsr166-tests/src/test/java/jsr166/LinkedTransferQueueTest.java72
-rw-r--r--jsr166-tests/src/test/java/jsr166/LockSupportTest.java16
-rw-r--r--jsr166-tests/src/test/java/jsr166/PhaserTest.java21
-rw-r--r--jsr166-tests/src/test/java/jsr166/PriorityBlockingQueueTest.java105
-rw-r--r--jsr166-tests/src/test/java/jsr166/PriorityQueueTest.java50
-rw-r--r--jsr166-tests/src/test/java/jsr166/RecursiveActionTest.java28
-rw-r--r--jsr166-tests/src/test/java/jsr166/RecursiveTaskTest.java21
-rw-r--r--jsr166-tests/src/test/java/jsr166/ReentrantLockTest.java58
-rw-r--r--jsr166-tests/src/test/java/jsr166/ReentrantReadWriteLockTest.java51
-rw-r--r--jsr166-tests/src/test/java/jsr166/ScheduledExecutorSubclassTest.java97
-rw-r--r--jsr166-tests/src/test/java/jsr166/ScheduledExecutorTest.java92
-rw-r--r--jsr166-tests/src/test/java/jsr166/SemaphoreTest.java22
-rw-r--r--jsr166-tests/src/test/java/jsr166/SynchronousQueueTest.java53
-rw-r--r--jsr166-tests/src/test/java/jsr166/SystemTest.java12
-rw-r--r--jsr166-tests/src/test/java/jsr166/ThreadLocalRandomTest.java134
-rw-r--r--jsr166-tests/src/test/java/jsr166/ThreadLocalTest.java15
-rw-r--r--jsr166-tests/src/test/java/jsr166/ThreadPoolExecutorSubclassTest.java43
-rw-r--r--jsr166-tests/src/test/java/jsr166/ThreadPoolExecutorTest.java39
-rw-r--r--jsr166-tests/src/test/java/jsr166/ThreadTest.java48
-rw-r--r--jsr166-tests/src/test/java/jsr166/TimeUnitTest.java245
-rw-r--r--jsr166-tests/src/test/java/jsr166/TreeMapTest.java37
-rw-r--r--jsr166-tests/src/test/java/jsr166/TreeSetTest.java70
-rw-r--r--jsr166-tests/src/test/java/jsr166/TreeSubMapTest.java35
-rw-r--r--jsr166-tests/src/test/java/jsr166/TreeSubSetTest.java87
-rw-r--r--libart/src/main/java/dalvik/system/TransactionAbortError.java62
-rw-r--r--libart/src/main/java/dalvik/system/VMRuntime.java42
-rw-r--r--libart/src/main/java/dalvik/system/VMStack.java7
-rw-r--r--libart/src/main/java/java/lang/AbstractStringBuilder.java (renamed from luni/src/main/java/java/lang/AbstractStringBuilder.java)19
-rw-r--r--libart/src/main/java/java/lang/CaseMapper.java (renamed from luni/src/main/java/java/lang/CaseMapper.java)76
-rw-r--r--libart/src/main/java/java/lang/Class.java404
-rw-r--r--libart/src/main/java/java/lang/ClassLoader.java4
-rw-r--r--libart/src/main/java/java/lang/Daemons.java128
-rw-r--r--libart/src/main/java/java/lang/DexCache.java18
-rw-r--r--libart/src/main/java/java/lang/Object.java7
-rw-r--r--libart/src/main/java/java/lang/String.java508
-rw-r--r--libart/src/main/java/java/lang/StringFactory.java251
-rw-r--r--libart/src/main/java/java/lang/Thread.java8
-rw-r--r--libart/src/main/java/java/lang/reflect/AbstractMethod.java86
-rw-r--r--libart/src/main/java/java/lang/reflect/AccessibleObject.java9
-rw-r--r--libart/src/main/java/java/lang/reflect/ArtField.java96
-rw-r--r--libart/src/main/java/java/lang/reflect/ArtMethod.java212
-rw-r--r--libart/src/main/java/java/lang/reflect/Constructor.java33
-rw-r--r--libart/src/main/java/java/lang/reflect/Field.java176
-rw-r--r--libart/src/main/java/java/lang/reflect/Method.java38
-rwxr-xr-x[-rw-r--r--]libart/src/main/java/java/lang/reflect/Proxy.java14
-rw-r--r--libart/src/main/java/sun/misc/Unsafe.java6
-rw-r--r--luni/src/benchmark/native/libcore_io_Memory_bench.cpp105
-rwxr-xr-xluni/src/main/files/README.cacerts2
-rw-r--r--luni/src/main/files/cacerts/0d188d89.080
-rw-r--r--luni/src/main/files/cacerts/0d5a4e1c.082
-rw-r--r--luni/src/main/files/cacerts/2afc57aa.091
-rw-r--r--luni/src/main/files/cacerts/2fb1850a.0124
-rw-r--r--luni/src/main/files/cacerts/3c6676aa.0120
-rw-r--r--luni/src/main/files/cacerts/4be590e0.0120
-rw-r--r--luni/src/main/files/cacerts/5021a0a2.084
-rw-r--r--luni/src/main/files/cacerts/5a250ea7.0120
-rw-r--r--luni/src/main/files/cacerts/6645de82.082
-rw-r--r--luni/src/main/files/cacerts/72fa7371.054
-rw-r--r--luni/src/main/files/cacerts/74c26bd0.060
-rw-r--r--luni/src/main/files/cacerts/7a481e66.091
-rw-r--r--luni/src/main/files/cacerts/9282e51c.0123
-rw-r--r--luni/src/main/files/cacerts/bda4cc84.082
-rw-r--r--luni/src/main/files/cacerts/c33a80d4.058
-rw-r--r--luni/src/main/files/cacerts/d18e9066.0120
-rw-r--r--luni/src/main/files/cacerts/d6e6eab9.0123
-rw-r--r--luni/src/main/files/cacerts/ddc328ff.057
-rw-r--r--luni/src/main/files/cacerts/e7b8d656.060
-rw-r--r--luni/src/main/files/cacerts/eb375c3e.077
-rw-r--r--luni/src/main/java/android/system/NetlinkSocketAddress.java61
-rw-r--r--luni/src/main/java/android/system/Os.java47
-rw-r--r--luni/src/main/java/android/system/OsConstants.java37
-rw-r--r--luni/src/main/java/android/system/PacketSocketAddress.java64
-rw-r--r--luni/src/main/java/java/io/BufferedInputStream.java2
-rw-r--r--luni/src/main/java/java/io/File.java12
-rw-r--r--luni/src/main/java/java/io/FileDescriptor.java2
-rw-r--r--luni/src/main/java/java/io/InputStreamReader.java4
-rw-r--r--luni/src/main/java/java/io/ObjectInputStream.java7
-rw-r--r--luni/src/main/java/java/io/ObjectStreamField.java8
-rw-r--r--luni/src/main/java/java/io/OutputStreamWriter.java5
-rw-r--r--luni/src/main/java/java/io/RandomAccessFile.java5
-rw-r--r--luni/src/main/java/java/lang/IllegalAccessError.java10
-rw-r--r--luni/src/main/java/java/lang/Math.java28
-rw-r--r--luni/src/main/java/java/lang/Package.java26
-rw-r--r--luni/src/main/java/java/lang/Runtime.java25
-rw-r--r--luni/src/main/java/java/lang/StrictMath.java1070
-rw-r--r--luni/src/main/java/java/lang/System.java125
-rw-r--r--luni/src/main/java/java/lang/ref/FinalizerReference.java21
-rw-r--r--luni/src/main/java/java/lang/reflect/Modifier.java19
-rw-r--r--luni/src/main/java/java/net/DatagramSocket.java24
-rw-r--r--luni/src/main/java/java/net/DatagramSocketImpl.java6
-rw-r--r--luni/src/main/java/java/net/HttpURLConnection.java20
-rw-r--r--luni/src/main/java/java/net/Inet6Address.java2
-rw-r--r--luni/src/main/java/java/net/InetAddress.java21
-rw-r--r--luni/src/main/java/java/net/InetSocketAddress.java45
-rw-r--r--luni/src/main/java/java/net/PlainSocketImpl.java10
-rw-r--r--luni/src/main/java/java/net/ServerSocket.java17
-rw-r--r--luni/src/main/java/java/net/Socket.java26
-rw-r--r--luni/src/main/java/java/net/URL.java2
-rw-r--r--luni/src/main/java/java/nio/SelectorImpl.java7
-rw-r--r--luni/src/main/java/java/nio/channels/Selector.java15
-rw-r--r--luni/src/main/java/java/nio/charset/CharsetEncoder.java46
-rw-r--r--luni/src/main/java/java/security/Provider.java4
-rw-r--r--luni/src/main/java/java/security/Security.java22
-rw-r--r--luni/src/main/java/java/security/Signature.java61
-rw-r--r--luni/src/main/java/java/text/BreakIterator.java38
-rw-r--r--luni/src/main/java/java/text/ChoiceFormat.java78
-rw-r--r--luni/src/main/java/java/text/DecimalFormatSymbols.java52
-rw-r--r--luni/src/main/java/java/text/Format.java11
-rw-r--r--luni/src/main/java/java/text/IcuIteratorWrapper.java (renamed from luni/src/main/java/java/text/RuleBasedBreakIterator.java)47
-rw-r--r--luni/src/main/java/java/text/MessageFormat.java6
-rw-r--r--luni/src/main/java/java/text/NumberFormat.java8
-rw-r--r--luni/src/main/java/java/text/SimpleDateFormat.java11
-rw-r--r--luni/src/main/java/java/util/Calendar.java4
-rw-r--r--luni/src/main/java/java/util/Collections.java82
-rw-r--r--luni/src/main/java/java/util/ComparableTimSort.java27
-rw-r--r--luni/src/main/java/java/util/Date.java29
-rw-r--r--luni/src/main/java/java/util/EnumMap.java139
-rw-r--r--luni/src/main/java/java/util/List.java7
-rw-r--r--luni/src/main/java/java/util/Locale.java159
-rw-r--r--luni/src/main/java/java/util/TimSort.java28
-rw-r--r--luni/src/main/java/java/util/TimeZone.java82
-rw-r--r--luni/src/main/java/java/util/concurrent/AbstractExecutorService.java1
-rw-r--r--luni/src/main/java/java/util/concurrent/ArrayBlockingQueue.java161
-rw-r--r--luni/src/main/java/java/util/concurrent/BlockingDeque.java10
-rw-r--r--luni/src/main/java/java/util/concurrent/BlockingQueue.java1
-rw-r--r--luni/src/main/java/java/util/concurrent/ConcurrentHashMap.java425
-rw-r--r--luni/src/main/java/java/util/concurrent/ConcurrentLinkedQueue.java6
-rw-r--r--luni/src/main/java/java/util/concurrent/ConcurrentMap.java1
-rw-r--r--luni/src/main/java/java/util/concurrent/ConcurrentNavigableMap.java1
-rw-r--r--luni/src/main/java/java/util/concurrent/ConcurrentSkipListMap.java31
-rw-r--r--luni/src/main/java/java/util/concurrent/ConcurrentSkipListSet.java1
-rw-r--r--luni/src/main/java/java/util/concurrent/CopyOnWriteArraySet.java1
-rw-r--r--luni/src/main/java/java/util/concurrent/CountDownLatch.java1
-rw-r--r--luni/src/main/java/java/util/concurrent/CountedCompleter.java2
-rw-r--r--luni/src/main/java/java/util/concurrent/CyclicBarrier.java3
-rw-r--r--luni/src/main/java/java/util/concurrent/DelayQueue.java3
-rw-r--r--luni/src/main/java/java/util/concurrent/Exchanger.java3
-rw-r--r--luni/src/main/java/java/util/concurrent/Executor.java6
-rw-r--r--luni/src/main/java/java/util/concurrent/ExecutorCompletionService.java2
-rw-r--r--luni/src/main/java/java/util/concurrent/ExecutorService.java5
-rw-r--r--luni/src/main/java/java/util/concurrent/Executors.java1
-rw-r--r--luni/src/main/java/java/util/concurrent/ForkJoinPool.java13
-rw-r--r--luni/src/main/java/java/util/concurrent/ForkJoinTask.java18
-rw-r--r--luni/src/main/java/java/util/concurrent/FutureTask.java106
-rw-r--r--luni/src/main/java/java/util/concurrent/LinkedTransferQueue.java7
-rw-r--r--luni/src/main/java/java/util/concurrent/Phaser.java6
-rw-r--r--luni/src/main/java/java/util/concurrent/PriorityBlockingQueue.java2
-rw-r--r--luni/src/main/java/java/util/concurrent/RecursiveTask.java1
-rw-r--r--luni/src/main/java/java/util/concurrent/ScheduledExecutorService.java8
-rw-r--r--luni/src/main/java/java/util/concurrent/ScheduledThreadPoolExecutor.java122
-rw-r--r--luni/src/main/java/java/util/concurrent/Semaphore.java1
-rw-r--r--luni/src/main/java/java/util/concurrent/SynchronousQueue.java10
-rw-r--r--luni/src/main/java/java/util/concurrent/ThreadLocalRandom.java4
-rw-r--r--luni/src/main/java/java/util/concurrent/ThreadPoolExecutor.java5
-rw-r--r--luni/src/main/java/java/util/concurrent/TimeUnit.java73
-rw-r--r--luni/src/main/java/java/util/concurrent/atomic/AtomicBoolean.java1
-rw-r--r--luni/src/main/java/java/util/concurrent/atomic/AtomicInteger.java1
-rw-r--r--luni/src/main/java/java/util/concurrent/atomic/AtomicIntegerArray.java1
-rw-r--r--luni/src/main/java/java/util/concurrent/atomic/AtomicIntegerFieldUpdater.java5
-rw-r--r--luni/src/main/java/java/util/concurrent/atomic/AtomicLong.java1
-rw-r--r--luni/src/main/java/java/util/concurrent/atomic/AtomicLongArray.java1
-rw-r--r--luni/src/main/java/java/util/concurrent/atomic/AtomicLongFieldUpdater.java4
-rw-r--r--luni/src/main/java/java/util/concurrent/atomic/AtomicMarkableReference.java2
-rw-r--r--luni/src/main/java/java/util/concurrent/atomic/AtomicReference.java1
-rw-r--r--luni/src/main/java/java/util/concurrent/atomic/AtomicReferenceFieldUpdater.java12
-rw-r--r--luni/src/main/java/java/util/concurrent/atomic/AtomicStampedReference.java2
-rw-r--r--luni/src/main/java/java/util/concurrent/locks/AbstractOwnableSynchronizer.java16
-rw-r--r--luni/src/main/java/java/util/concurrent/locks/AbstractQueuedLongSynchronizer.java25
-rw-r--r--luni/src/main/java/java/util/concurrent/locks/AbstractQueuedSynchronizer.java25
-rw-r--r--luni/src/main/java/java/util/concurrent/locks/Condition.java1
-rw-r--r--luni/src/main/java/java/util/concurrent/locks/Lock.java1
-rw-r--r--luni/src/main/java/java/util/concurrent/locks/LockSupport.java1
-rw-r--r--luni/src/main/java/java/util/concurrent/locks/ReentrantLock.java1
-rw-r--r--luni/src/main/java/java/util/concurrent/locks/ReentrantReadWriteLock.java9
-rw-r--r--luni/src/main/java/java/util/concurrent/package-info.java34
-rw-r--r--luni/src/main/java/java/util/jar/Manifest.java26
-rw-r--r--luni/src/main/java/java/util/jar/StrictJarFile.java14
-rw-r--r--luni/src/main/java/java/util/logging/FileHandler.java14
-rw-r--r--luni/src/main/java/java/util/logging/SocketHandler.java10
-rw-r--r--luni/src/main/java/java/util/logging/XMLFormatter.java66
-rw-r--r--luni/src/main/java/java/util/zip/GZIPInputStream.java4
-rw-r--r--luni/src/main/java/java/util/zip/Zip64.java415
-rw-r--r--luni/src/main/java/java/util/zip/ZipEntry.java33
-rw-r--r--luni/src/main/java/java/util/zip/ZipFile.java95
-rw-r--r--luni/src/main/java/java/util/zip/ZipInputStream.java33
-rw-r--r--luni/src/main/java/java/util/zip/ZipOutputStream.java285
-rw-r--r--luni/src/main/java/javax/crypto/Cipher.java304
-rw-r--r--luni/src/main/java/javax/crypto/ExemptionMechanism.java3
-rw-r--r--luni/src/main/java/javax/crypto/KeyAgreement.java61
-rw-r--r--luni/src/main/java/javax/crypto/Mac.java62
-rw-r--r--luni/src/main/java/javax/net/ssl/DefaultHostnameVerifier.java169
-rw-r--r--luni/src/main/java/javax/net/ssl/HttpsURLConnection.java11
-rw-r--r--luni/src/main/java/javax/net/ssl/SSLEngine.java364
-rw-r--r--luni/src/main/java/javax/net/ssl/SSLSocket.java372
-rw-r--r--luni/src/main/java/javax/security/cert/X509Certificate.java4
-rw-r--r--luni/src/main/java/javax/xml/datatype/FactoryFinder.java44
-rw-r--r--luni/src/main/java/javax/xml/validation/SchemaFactoryFinder.java47
-rw-r--r--luni/src/main/java/javax/xml/xpath/XPathFactoryFinder.java47
-rw-r--r--luni/src/main/java/libcore/icu/DateIntervalFormat.java199
-rw-r--r--luni/src/main/java/libcore/icu/DateTimeFormat.java58
-rw-r--r--luni/src/main/java/libcore/icu/DateUtilsBridge.java177
-rw-r--r--luni/src/main/java/libcore/icu/ICU.java3
-rw-r--r--luni/src/main/java/libcore/icu/LocaleData.java11
-rw-r--r--luni/src/main/java/libcore/icu/NativeBreakIterator.java177
-rw-r--r--luni/src/main/java/libcore/icu/RelativeDateTimeFormatter.java360
-rw-r--r--luni/src/main/java/libcore/io/BlockGuardOs.java2
-rw-r--r--luni/src/main/java/libcore/io/ForwardingOs.java16
-rw-r--r--luni/src/main/java/libcore/io/IoBridge.java6
-rw-r--r--luni/src/main/java/libcore/io/IoUtils.java6
-rw-r--r--luni/src/main/java/libcore/io/Os.java16
-rw-r--r--luni/src/main/java/libcore/io/Posix.java19
-rw-r--r--luni/src/main/java/libcore/net/MimeUtils.java65
-rw-r--r--luni/src/main/java/libcore/net/NetworkSecurityPolicy.java66
-rw-r--r--luni/src/main/java/libcore/net/http/ResponseUtils.java90
-rw-r--r--luni/src/main/java/libcore/net/url/FtpURLConnection.java13
-rw-r--r--luni/src/main/java/libcore/util/CharsetUtils.java (renamed from luni/src/main/java/java/nio/charset/Charsets.java)32
-rw-r--r--luni/src/main/java/libcore/util/CountingOutputStream.java59
-rw-r--r--luni/src/main/java/libcore/util/HexEncoding.java99
-rw-r--r--luni/src/main/java/libcore/util/ZoneInfo.java31
-rw-r--r--luni/src/main/java/libcore/util/ZoneInfoDB.java7
-rw-r--r--luni/src/main/java/org/apache/harmony/security/fortress/Engine.java6
-rw-r--r--luni/src/main/java/org/apache/harmony/security/fortress/Services.java123
-rw-r--r--luni/src/main/java/org/apache/harmony/security/utils/JarUtils.java4
-rw-r--r--luni/src/main/java/org/apache/harmony/security/utils/WrappedX509Certificate.java2
-rw-r--r--luni/src/main/native/IcuUtilities.cpp5
-rw-r--r--luni/src/main/native/IcuUtilities.h5
-rw-r--r--luni/src/main/native/Portability.h32
-rw-r--r--luni/src/main/native/Register.cpp3
-rw-r--r--luni/src/main/native/ZipUtilities.cpp7
-rw-r--r--luni/src/main/native/ZipUtilities.h9
-rw-r--r--luni/src/main/native/android_system_OsConstants.cpp38
-rw-r--r--luni/src/main/native/java_lang_RealToString.cpp4
-rw-r--r--luni/src/main/native/java_lang_StrictMath.cpp65
-rw-r--r--luni/src/main/native/java_lang_StringToReal.cpp151
-rw-r--r--luni/src/main/native/java_lang_System.cpp21
-rw-r--r--luni/src/main/native/java_math_NativeBN.cpp66
-rw-r--r--luni/src/main/native/java_nio_charset_Charsets.cpp250
-rw-r--r--luni/src/main/native/java_text_Bidi.cpp10
-rw-r--r--luni/src/main/native/java_util_jar_StrictJarFile.cpp71
-rw-r--r--luni/src/main/native/java_util_regex_Matcher.cpp13
-rw-r--r--luni/src/main/native/java_util_regex_Pattern.cpp8
-rw-r--r--luni/src/main/native/java_util_zip_Deflater.cpp11
-rw-r--r--luni/src/main/native/java_util_zip_Inflater.cpp11
-rw-r--r--luni/src/main/native/libcore_icu_AlphabeticIndex.cpp42
-rw-r--r--luni/src/main/native/libcore_icu_DateIntervalFormat.cpp79
-rw-r--r--luni/src/main/native/libcore_icu_ICU.cpp249
-rw-r--r--luni/src/main/native/libcore_icu_NativeBreakIterator.cpp223
-rw-r--r--luni/src/main/native/libcore_icu_NativeCollation.cpp6
-rw-r--r--luni/src/main/native/libcore_icu_NativeConverter.cpp20
-rw-r--r--luni/src/main/native/libcore_icu_NativeDecimalFormat.cpp119
-rw-r--r--luni/src/main/native/libcore_icu_NativeIDN.cpp9
-rw-r--r--luni/src/main/native/libcore_icu_NativeNormalizer.cpp6
-rw-r--r--luni/src/main/native/libcore_icu_NativePluralRules.cpp10
-rw-r--r--luni/src/main/native/libcore_icu_TimeZoneNames.cpp45
-rw-r--r--luni/src/main/native/libcore_icu_Transliterator.cpp12
-rw-r--r--luni/src/main/native/libcore_io_Memory.cpp106
-rw-r--r--luni/src/main/native/libcore_io_Posix.cpp428
-rw-r--r--luni/src/main/native/org_apache_harmony_xml_ExpatParser.cpp9
-rw-r--r--luni/src/main/native/sub.mk10
-rw-r--r--luni/src/test/java/com/android/org/bouncycastle/crypto/digests/DigestTest.java33
-rw-r--r--luni/src/test/java/com/android/org/bouncycastle/jce/provider/CertBlacklistTest.java15
-rw-r--r--luni/src/test/java/libcore/dalvik/system/PathClassLoaderTest.java23
-rw-r--r--luni/src/test/java/libcore/icu/DateIntervalFormatTest.java142
-rw-r--r--luni/src/test/java/libcore/icu/ICUTest.java27
-rw-r--r--luni/src/test/java/libcore/icu/LocaleDataTest.java12
-rw-r--r--luni/src/test/java/libcore/icu/RelativeDateTimeFormatterTest.java667
-rw-r--r--luni/src/test/java/libcore/io/OsTest.java229
-rw-r--r--luni/src/test/java/libcore/java/io/FileDescriptorTest.java6
-rw-r--r--luni/src/test/java/libcore/java/io/FileInputStreamTest.java2
-rw-r--r--luni/src/test/java/libcore/java/io/RandomAccessFileTest.java57
-rw-r--r--luni/src/test/java/libcore/java/lang/FloatTest.java16
-rwxr-xr-x[-rw-r--r--]luni/src/test/java/libcore/java/lang/OldAndroidMonitorTest.java14
-rw-r--r--luni/src/test/java/libcore/java/lang/OldClassTest.java5
-rw-r--r--luni/src/test/java/libcore/java/lang/OldSystemTest.java8
-rw-r--r--luni/src/test/java/libcore/java/lang/PackageTest.java7
-rw-r--r--luni/src/test/java/libcore/java/lang/ProcessBuilderTest.java2
-rw-r--r--luni/src/test/java/libcore/java/lang/StringTest.java41
-rw-r--r--luni/src/test/java/libcore/java/lang/TestPackageAnnotation.java26
-rw-r--r--luni/src/test/java/libcore/java/lang/package-info.java18
-rw-r--r--luni/src/test/java/libcore/java/lang/reflect/FieldTest.java52
-rw-r--r--luni/src/test/java/libcore/java/lang/reflect/MethodTest.java18
-rw-r--r--luni/src/test/java/libcore/java/lang/reflect/ModifierTest.java5
-rw-r--r--luni/src/test/java/libcore/java/net/InetAddressTest.java86
-rw-r--r--luni/src/test/java/libcore/java/net/InetSocketAddressTest.java32
-rw-r--r--luni/src/test/java/libcore/java/net/OldSocketTest.java27
-rw-r--r--luni/src/test/java/libcore/java/net/SocketTest.java33
-rw-r--r--luni/src/test/java/libcore/java/net/URLConnectionTest.java659
-rw-r--r--luni/src/test/java/libcore/java/nio/channels/SelectorTest.java21
-rw-r--r--luni/src/test/java/libcore/java/nio/charset/CharsetEncoderTest.java69
-rw-r--r--luni/src/test/java/libcore/java/nio/charset/SettableCharsetProvider.java57
-rw-r--r--luni/src/test/java/libcore/java/security/KeyPairGeneratorTest.java47
-rw-r--r--luni/src/test/java/libcore/java/security/ProviderTest.java24
-rw-r--r--luni/src/test/java/libcore/java/security/SecureRandomTest.java1
-rw-r--r--luni/src/test/java/libcore/java/security/SignatureTest.java106
-rw-r--r--luni/src/test/java/libcore/java/security/cert/CertificateFactoryTest.java40
-rw-r--r--luni/src/test/java/libcore/java/security/cert/X509CRLTest.java10
-rw-r--r--luni/src/test/java/libcore/java/security/cert/X509CertificateTest.java7
-rw-r--r--luni/src/test/java/libcore/java/sql/TimestampTest.java8
-rw-r--r--luni/src/test/java/libcore/java/text/BreakIteratorTest.java28
-rw-r--r--luni/src/test/java/libcore/java/text/DateFormatSymbolsTest.java14
-rw-r--r--luni/src/test/java/libcore/java/text/DecimalFormatSymbolsTest.java30
-rw-r--r--luni/src/test/java/libcore/java/text/NumberFormatTest.java16
-rw-r--r--luni/src/test/java/libcore/java/util/CalendarTest.java72
-rw-r--r--luni/src/test/java/libcore/java/util/CollectionsTest.java91
-rw-r--r--luni/src/test/java/libcore/java/util/CurrencyTest.java2
-rw-r--r--luni/src/test/java/libcore/java/util/DateTest.java11
-rw-r--r--luni/src/test/java/libcore/java/util/LocaleTest.java91
-rw-r--r--luni/src/test/java/libcore/java/util/OldTimeZoneTest.java14
-rw-r--r--luni/src/test/java/libcore/java/util/TimSortTest.java82
-rw-r--r--luni/src/test/java/libcore/java/util/TimeZoneTest.java46
-rw-r--r--luni/src/test/java/libcore/java/util/jar/StrictJarFileTest.java4
-rw-r--r--luni/src/test/java/libcore/java/util/zip/AbstractZipFileTest.java548
-rw-r--r--luni/src/test/java/libcore/java/util/zip/DeflaterTest.java22
-rw-r--r--luni/src/test/java/libcore/java/util/zip/GZIPInputStreamTest.java36
-rw-r--r--luni/src/test/java/libcore/java/util/zip/InflaterTest.java31
-rw-r--r--luni/src/test/java/libcore/java/util/zip/Zip64FileTest.java102
-rw-r--r--luni/src/test/java/libcore/java/util/zip/Zip64Test.java100
-rw-r--r--luni/src/test/java/libcore/java/util/zip/ZipEntryTest.java34
-rw-r--r--luni/src/test/java/libcore/java/util/zip/ZipFileTest.java491
-rw-r--r--luni/src/test/java/libcore/java/util/zip/ZipOutputStreamTest.java1
-rw-r--r--luni/src/test/java/libcore/javax/crypto/CipherTest.java638
-rw-r--r--luni/src/test/java/libcore/javax/crypto/ECDHKeyAgreementTest.java23
-rw-r--r--luni/src/test/java/libcore/javax/crypto/KeyAgreementTest.java95
-rw-r--r--luni/src/test/java/libcore/javax/crypto/KeyGeneratorTest.java9
-rw-r--r--luni/src/test/java/libcore/javax/crypto/MacTest.java62
-rw-r--r--luni/src/test/java/libcore/javax/crypto/MockCipherSpi.java87
-rw-r--r--luni/src/test/java/libcore/javax/crypto/MockKey.java2
-rw-r--r--luni/src/test/java/libcore/javax/crypto/MockKeyAgreementSpi.java91
-rw-r--r--luni/src/test/java/libcore/javax/crypto/MockMacSpi.java92
-rw-r--r--luni/src/test/java/libcore/javax/net/ssl/DefaultHostnameVerifierTest.java373
-rw-r--r--luni/src/test/java/libcore/javax/net/ssl/HttpsURLConnectionTest.java115
-rw-r--r--luni/src/test/java/libcore/javax/net/ssl/SSLContextTest.java26
-rw-r--r--luni/src/test/java/libcore/javax/net/ssl/SSLEngineTest.java124
-rw-r--r--luni/src/test/java/libcore/javax/net/ssl/SSLServerSocketFactoryTest.java2
-rw-r--r--luni/src/test/java/libcore/javax/net/ssl/SSLServerSocketTest.java2
-rw-r--r--luni/src/test/java/libcore/javax/net/ssl/SSLSessionTest.java2
-rw-r--r--luni/src/test/java/libcore/javax/net/ssl/SSLSocketFactoryTest.java2
-rw-r--r--luni/src/test/java/libcore/javax/net/ssl/SSLSocketTest.java249
-rw-r--r--luni/src/test/java/libcore/net/MimeUtilsTest.java6
-rw-r--r--luni/src/test/java/libcore/net/NetworkSecurityPolicyTest.java315
-rw-r--r--luni/src/test/java/libcore/net/http/ResponseUtilsTest.java52
-rw-r--r--luni/src/test/java/libcore/util/HexEncodingTest.java78
-rw-r--r--luni/src/test/java/libcore/util/ZoneInfoDBTest.java7
-rw-r--r--luni/src/test/java/org/apache/harmony/crypto/tests/javax/crypto/ExemptionMechanismTest.java41
-rw-r--r--luni/src/test/java/org/apache/harmony/crypto/tests/javax/crypto/MacTest.java40
-rw-r--r--luni/src/test/java/org/apache/harmony/security/tests/java/security/Signature2Test.java15
-rw-r--r--luni/src/test/java/tests/security/cert/CertificateTest.java15
-rw-r--r--luni/src/test/java/tests/security/interfaces/DSAPrivateKeyTest.java4
-rw-r--r--luni/src/test/java/tests/security/interfaces/DSAPublicKeyTest.java4
-rw-r--r--luni/src/test/native/libcore_io_Memory_test.cpp134
-rw-r--r--luni/src/test/native/test_openssl_engine.cpp132
-rw-r--r--luni/src/test/resources/META-INF/services/java.nio.charset.spi.CharsetProvider1
-rwxr-xr-xrun-libcore-tests2
-rw-r--r--support/src/test/java/libcore/java/security/StandardNames.java243
-rw-r--r--support/src/test/java/libcore/javax/net/ssl/SSLConfigurationAsserts.java248
-rw-r--r--support/src/test/java/libcore/javax/net/ssl/SSLDefaultConfigurationAsserts.java202
-rw-r--r--support/src/test/java/libcore/javax/net/ssl/TestSSLEnginePair.java18
-rw-r--r--support/src/test/java/libcore/tlswire/handshake/CipherSuite.java464
-rw-r--r--support/src/test/java/libcore/tlswire/handshake/ClientHello.java108
-rw-r--r--support/src/test/java/libcore/tlswire/handshake/CompressionMethod.java76
-rw-r--r--support/src/test/java/libcore/tlswire/handshake/HandshakeMessage.java62
-rw-r--r--support/src/test/java/libcore/tlswire/handshake/HelloExtension.java100
-rw-r--r--support/src/test/java/libcore/tlswire/handshake/ServerNameHelloExtension.java56
-rw-r--r--support/src/test/java/libcore/tlswire/record/TlsProtocols.java30
-rw-r--r--support/src/test/java/libcore/tlswire/record/TlsRecord.java40
-rw-r--r--support/src/test/java/libcore/tlswire/util/IoUtils.java59
-rw-r--r--support/src/test/java/libcore/tlswire/util/TlsProtocolVersion.java97
-rw-r--r--support/src/test/java/tests/net/StuckServer.java21
-rw-r--r--support/src/test/java/tests/resources/removed.jarbin0 -> 1721 bytes
-rw-r--r--support/src/test/java/tests/support/Support_Configuration.java383
-rw-r--r--support/src/test/java/tests/util/DelegatingSSLSocketFactory.java101
-rw-r--r--support/src/test/java/tests/util/ForEachRunner.java54
-rw-r--r--support/src/test/java/tests/util/Pair.java107
-rw-r--r--support/src/test/java/tests/util/SummaryStatistics.java82
-rw-r--r--tzdata/Android.mk51
-rwxr-xr-xtzdata/tools/createIcuUpdateResources.sh89
-rwxr-xr-xtzdata/tools/createTzDataBundle.sh25
-rw-r--r--tzdata/tools/src/main/libcore/tzdata/update/tools/CreateTzDataBundle.java127
-rw-r--r--tzdata/tools/src/main/libcore/tzdata/update/tools/TzDataBundleBuilder.java134
-rw-r--r--tzdata/tools/tzupdate.properties14
-rw-r--r--tzdata/update/src/main/libcore/tzdata/update/ConfigBundle.java123
-rw-r--r--tzdata/update/src/main/libcore/tzdata/update/FileUtils.java197
-rw-r--r--tzdata/update/src/main/libcore/tzdata/update/TzDataBundleInstaller.java141
-rw-r--r--tzdata/update/src/test/libcore/tzdata/update/ConfigBundleTest.java151
-rw-r--r--tzdata/update/src/test/libcore/tzdata/update/FileUtilsTest.java329
-rw-r--r--tzdata/update/src/test/libcore/tzdata/update/TzDataBundleInstallerTest.java210
-rw-r--r--tzdata/update_test_app/Android.mk25
-rw-r--r--tzdata/update_test_app/AndroidManifest.xml34
-rw-r--r--tzdata/update_test_app/res/drawable/ic_launcher.pngbin0 -> 9397 bytes
-rw-r--r--tzdata/update_test_app/res/layout/activity_main.xml106
-rw-r--r--tzdata/update_test_app/res/values/strings.xml13
-rw-r--r--tzdata/update_test_app/res/xml/filepaths.xml4
-rw-r--r--tzdata/update_test_app/src/libcore/tzdata/update_test_app/installupdatetestapp/MainActivity.java173
516 files changed, 21960 insertions, 9510 deletions
diff --git a/Android.mk b/Android.mk
index fd9bcd1..dcc783e 100644
--- a/Android.mk
+++ b/Android.mk
@@ -19,7 +19,7 @@ LOCAL_PATH := $(call my-dir)
# Subprojects with separate makefiles
#
-subdirs := benchmarks
+subdirs := benchmarks tzdata
subdir_makefiles := $(call all-named-subdir-makefiles,$(subdirs))
#
diff --git a/Docs.mk b/Docs.mk
index a163d1f..0c52bf5 100644
--- a/Docs.mk
+++ b/Docs.mk
@@ -20,11 +20,20 @@ libcore_to_document := \
libart/src/main/java/dalvik \
libart/src/main/java/java \
luni/src/main/java/android \
- luni/src/main/java/java \
luni/src/main/java/javax \
luni/src/main/java/org/xml/sax \
luni/src/main/java/org/w3c \
xml/src/main/java/org/xmlpull/v1)
+# IcuIteratorWrapper.java references com.ibm.icu.text.BreakIterator,
+# which is renamed by our jarjar rule, and so unrecognizable by javadoc,
+# with annoying error: error: package com.ibm.icu.text does not exist.
+# We don't want to generate doc for this file anyway.
+libcore_to_document += \
+ $(filter-out luni/src/main/java/java/text/IcuIteratorWrapper.java,\
+ $(call find-files-in-subdirs, libcore, \
+ "*.java", \
+ luni/src/main/java/java))
+
libcore_docs_include_once := 1
endif # libcore_docs_include_once
diff --git a/JavaLibrary.mk b/JavaLibrary.mk
index 57a8f82..9f6d827 100644
--- a/JavaLibrary.mk
+++ b/JavaLibrary.mk
@@ -69,14 +69,43 @@ local_javac_flags=-encoding UTF-8
local_javac_flags+=-Xmaxwarns 9999999
#
+# ICU4J related rules.
+#
+# We compile icu4j along with core-libart because we're implementing parts of core-libart
+# in terms of icu4j.
+icu4j_root := ../external/icu/icu4j/
+icu4j_src_files := $(call all-java-files-under,$(icu4j_root)/main/classes)
+
+# Filter out bits of ICU4J we don't use yet : the SPIs (which we have limited support for),
+# the charset encoders and the transliterators.
+icu4j_src_files := $(filter-out $(icu4j_root)/main/classes/localespi/%, $(icu4j_src_files))
+icu4j_src_files := $(filter-out $(icu4j_root)/main/classes/charset/%, $(icu4j_src_files))
+icu4j_src_files := $(filter-out $(icu4j_root)/main/classes/translit/%, $(icu4j_src_files))
+
+# Not all src dirs contain resources, some instead contain other random files
+# that should not be included as resources. The ones that should be included
+# can be identifed by the fact that they contain particular subdir trees.
+#
+define all-icu-subdir-with-subdir
+$(patsubst $(LOCAL_PATH)/%/$(2),%,$(wildcard $(LOCAL_PATH)/$(1)/$(2)))
+endef
+
+icu4j_resource_dirs := $(call all-icu-subdir-with-subdir,$(icu4j_root)/main/classes/*/src,com/ibm/icu)
+icu4j_resource_dirs := $(filter-out $(icu4j_root)/main/classes/localespi/%, $(icu4j_resource_dirs))
+icu4j_resource_dirs := $(filter-out $(icu4j_root)/main/classes/charset/%, $(icu4j_resource_dirs))
+icu4j_resource_dirs := $(filter-out $(icu4j_root)/main/classes/translit/%, $(icu4j_resource_dirs))
+
+
+
+#
# Build for the target (device).
#
# Definitions to make the core library.
include $(CLEAR_VARS)
-LOCAL_SRC_FILES := $(libart_core_src_files)
-LOCAL_JAVA_RESOURCE_DIRS := $(core_resource_dirs)
+LOCAL_SRC_FILES := $(libart_core_src_files) $(icu4j_src_files)
+LOCAL_JAVA_RESOURCE_DIRS := $(core_resource_dirs) $(icu4j_resource_dirs)
LOCAL_NO_STANDARD_LIBRARIES := true
LOCAL_JAVACFLAGS := $(local_javac_flags)
LOCAL_DX_FLAGS := --core-library
@@ -84,8 +113,19 @@ LOCAL_MODULE_TAGS := optional
LOCAL_MODULE := core-libart
LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/JavaLibrary.mk
LOCAL_REQUIRED_MODULES := tzdata
+LOCAL_JARJAR_RULES := $(LOCAL_PATH)/jarjar-rules.txt
include $(BUILD_JAVA_LIBRARY)
+# Path to the ICU4C data files in the Android device file system:
+icu4c_data := /system/usr/icu
+# TODO: It's quite hideous that this double-slash between icu4j and main is required.
+# It's because we provide a variable substition of the make-rule generated jar command
+# to substitute a processed ICUProperties.config file in place of the original.
+#
+# We can avoid this by filtering out ICUConfig.properties from our list of resources.
+icu4j_config_root := $(LOCAL_PATH)/../external/icu/icu4j//main/classes/core/src
+include external/icu/icu4j/adjust_icudt_path.mk
+
ifeq ($(LIBCORE_SKIP_TESTS),)
# Make the core-tests library.
include $(CLEAR_VARS)
@@ -126,25 +166,12 @@ LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/JavaLibrary.mk
include $(BUILD_STATIC_JAVA_LIBRARY)
endif
-# This one's tricky. One of our tests needs to have a
-# resource with a "#" in its name, but Perforce doesn't
-# allow us to submit such a file. So we create it here
-# on-the-fly.
-TMP_RESOURCE_DIR := $(intermediates.COMMON)/tmp/
-TMP_RESOURCE_FILE := org/apache/harmony/luni/tests/java/lang/test\#.properties
-
-$(TMP_RESOURCE_DIR)$(TMP_RESOURCE_FILE):
- @mkdir -p $(dir $@)
- @echo "Hello, world!" > $@
-
-$(LOCAL_INTERMEDIATE_TARGETS): PRIVATE_EXTRA_JAR_ARGS := $(extra_jar_args) -C "$(TMP_RESOURCE_DIR)" "$(TMP_RESOURCE_FILE)"
-$(LOCAL_INTERMEDIATE_TARGETS): $(TMP_RESOURCE_DIR)$(TMP_RESOURCE_FILE)
-
-
#
# Build for the host.
#
+ifeq ($(HOST_OS),linux)
+
include $(CLEAR_VARS)
LOCAL_SRC_FILES := $(call all-main-java-files-under, dex)
LOCAL_MODULE_TAGS := optional
@@ -153,8 +180,8 @@ include $(BUILD_HOST_JAVA_LIBRARY)
# Definitions to make the core library.
include $(CLEAR_VARS)
-LOCAL_SRC_FILES := $(libart_core_src_files)
-LOCAL_JAVA_RESOURCE_DIRS := $(core_resource_dirs)
+LOCAL_SRC_FILES := $(libart_core_src_files) $(icu4j_src_files)
+LOCAL_JAVA_RESOURCE_DIRS := $(core_resource_dirs) $(icu4j_resource_dirs)
LOCAL_NO_STANDARD_LIBRARIES := true
LOCAL_JAVACFLAGS := $(local_javac_flags)
LOCAL_DX_FLAGS := --core-library
@@ -162,6 +189,7 @@ LOCAL_MODULE_TAGS := optional
LOCAL_MODULE := core-libart-hostdex
LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/JavaLibrary.mk
LOCAL_REQUIRED_MODULES := tzdata-host
+LOCAL_JARJAR_RULES := $(LOCAL_PATH)/jarjar-rules.txt
include $(BUILD_HOST_DALVIK_JAVA_LIBRARY)
# Make the core-tests library.
@@ -193,6 +221,8 @@ ifeq ($(LIBCORE_SKIP_TESTS),)
include $(BUILD_HOST_DALVIK_JAVA_LIBRARY)
endif
+endif # HOST_OS == linux
+
#
# Local droiddoc for faster libcore testing
#
diff --git a/NOTICE b/NOTICE
index 951e506..5136b4b 100644
--- a/NOTICE
+++ b/NOTICE
@@ -104,3 +104,14 @@ WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See W3C License http://www.w3.org/Consortium/Legal/ for more details.
+
+ =========================================================================
+ == NOTICE file for the fdlibm License. ==
+ =========================================================================
+
+Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+
+Developed at SunSoft, a Sun Microsystems, Inc. business.
+Permission to use, copy, modify, and distribute this
+software is freely granted, provided that this notice
+is preserved.
diff --git a/NativeCode.mk b/NativeCode.mk
index 0ae615e..b21dd2d 100644
--- a/NativeCode.mk
+++ b/NativeCode.mk
@@ -67,11 +67,10 @@ core_c_includes := libcore/include $(LOCAL_C_INCLUDES)
core_shared_libraries := $(LOCAL_SHARED_LIBRARIES)
core_static_libraries := $(LOCAL_STATIC_LIBRARIES)
core_cflags := $(LOCAL_CFLAGS) -Wall -Wextra -Werror
-core_cppflags += -std=gnu++11
+core_cppflags += -std=gnu++11 -DU_USING_ICU_NAMESPACE=0
core_test_files := \
luni/src/test/native/dalvik_system_JniTest.cpp \
- luni/src/test/native/test_openssl_engine.cpp \
#
# Build for the target (device).
@@ -83,11 +82,11 @@ LOCAL_CPPFLAGS += $(core_cppflags)
LOCAL_SRC_FILES += $(core_src_files)
LOCAL_C_INCLUDES += $(core_c_includes)
LOCAL_SHARED_LIBRARIES += $(core_shared_libraries) libcrypto libdl libexpat libicuuc libicui18n libnativehelper libz libutils
-LOCAL_STATIC_LIBRARIES += $(core_static_libraries) libziparchive
+LOCAL_STATIC_LIBRARIES += $(core_static_libraries) libziparchive libbase
LOCAL_MODULE_TAGS := optional
LOCAL_MODULE := libjavacore
LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/NativeCode.mk
-include external/stlport/libstlport.mk
+LOCAL_CXX_STL := libc++
include $(BUILD_SHARED_LIBRARY)
# Test JNI library.
@@ -97,21 +96,54 @@ include $(CLEAR_VARS)
LOCAL_CFLAGS += $(core_cflags)
LOCAL_CPPFLAGS += $(core_cppflags)
LOCAL_SRC_FILES += $(core_test_files)
-LOCAL_C_INCLUDES += libcore/include external/openssl/include
+LOCAL_C_INCLUDES += libcore/include
LOCAL_SHARED_LIBRARIES += libcrypto
LOCAL_MODULE_TAGS := optional
LOCAL_MODULE := libjavacoretests
LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/NativeCode.mk
-include external/stlport/libstlport.mk
+LOCAL_CXX_STL := libc++
include $(BUILD_SHARED_LIBRARY)
endif # LIBCORE_SKIP_TESTS
+# Set of gtest unit tests.
+include $(CLEAR_VARS)
+LOCAL_CFLAGS += $(core_cflags)
+LOCAL_CPPFLAGS += $(core_cppflags)
+LOCAL_SRC_FILES += \
+ luni/src/test/native/libcore_io_Memory_test.cpp \
+
+LOCAL_C_INCLUDES += libcore/include
+LOCAL_MODULE_TAGS := debug
+LOCAL_MODULE := libjavacore-unit-tests
+LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/NativeCode.mk
+LOCAL_CXX_STL := libc++
+include $(BUILD_NATIVE_TEST)
+
+# Set of benchmarks for libjavacore functions.
+include $(CLEAR_VARS)
+LOCAL_CFLAGS += $(core_cflags)
+LOCAL_CPPFLAGS += $(core_cppflags)
+LOCAL_SRC_FILES += \
+ luni/src/benchmark/native/libcore_io_Memory_bench.cpp \
+
+LOCAL_C_INCLUDES += libcore/include bionic/benchmarks
+LOCAL_MODULE_TAGS := debug
+LOCAL_MODULE := libjavacore-benchmarks
+LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/NativeCode.mk
+LOCAL_CXX_STL := libc++
+LOCAL_MULTILIB := both
+LOCAL_MODULE_STEM_32 := $(LOCAL_MODULE)32
+LOCAL_MODULE_STEM_64 := $(LOCAL_MODULE)64
+include $(BUILD_NATIVE_BENCHMARK)
+
#
# Build for the host.
#
+ifeq ($(HOST_OS),linux)
+
include $(CLEAR_VARS)
LOCAL_CLANG := true
LOCAL_SRC_FILES += $(core_src_files)
@@ -125,9 +157,10 @@ endif
LOCAL_MODULE_TAGS := optional
LOCAL_MODULE := libjavacore
LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/NativeCode.mk
-LOCAL_SHARED_LIBRARIES += $(core_shared_libraries) libexpat-host libicuuc-host libicui18n-host libcrypto-host libz-host
-LOCAL_STATIC_LIBRARIES += $(core_static_libraries) libziparchive-host libutils
+LOCAL_SHARED_LIBRARIES += $(core_shared_libraries) libexpat-host libicuuc-host libicui18n-host libcrypto-host libz-host libziparchive-host
+LOCAL_STATIC_LIBRARIES += $(core_static_libraries)
LOCAL_MULTILIB := both
+LOCAL_CXX_STL := libc++
include $(BUILD_HOST_SHARED_LIBRARY)
ifeq ($(LIBCORE_SKIP_TESTS),)
@@ -135,12 +168,15 @@ ifeq ($(LIBCORE_SKIP_TESTS),)
LOCAL_CLANG := true
LOCAL_SRC_FILES += $(core_test_files)
LOCAL_CFLAGS += $(core_cflags)
- LOCAL_C_INCLUDES += libcore/include external/openssl/include
+ LOCAL_C_INCLUDES += libcore/include
LOCAL_CPPFLAGS += $(core_cppflags)
LOCAL_LDLIBS += -ldl -lpthread
LOCAL_MODULE_TAGS := optional
LOCAL_MODULE := libjavacoretests
LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/NativeCode.mk
LOCAL_SHARED_LIBRARIES := libcrypto-host
+ LOCAL_CXX_STL := libc++
include $(BUILD_HOST_SHARED_LIBRARY)
endif # LIBCORE_SKIP_TESTS
+
+endif # HOST_OS == linux
diff --git a/benchmarks/Android.mk b/benchmarks/Android.mk
index c0a38a0..9e65091 100644
--- a/benchmarks/Android.mk
+++ b/benchmarks/Android.mk
@@ -21,7 +21,7 @@ ifeq ($(LIBCORE_SKIP_TESTS),)
include $(CLEAR_VARS)
LOCAL_MODULE := benchmarks
LOCAL_SRC_FILES := $(call all-java-files-under, src)
-LOCAL_STATIC_JAVA_LIBRARIES := caliper-prebuilt core-tests
+LOCAL_STATIC_JAVA_LIBRARIES := caliper-prebuilt mockwebserver core-tests-support
LOCAL_NO_STANDARD_LIBRARIES := true
LOCAL_JAVA_LIBRARIES := core-libart conscrypt core-junit bouncycastle framework
LOCAL_MODULE_TAGS := tests
diff --git a/benchmarks/src/benchmarks/regression/BreakIteratorBenchmark.java b/benchmarks/src/benchmarks/regression/BreakIteratorBenchmark.java
new file mode 100644
index 0000000..8602ddc
--- /dev/null
+++ b/benchmarks/src/benchmarks/regression/BreakIteratorBenchmark.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package benchmarks.regression;
+
+import com.google.caliper.Param;
+import com.google.caliper.SimpleBenchmark;
+
+import java.text.BreakIterator;
+import java.util.Locale;
+
+public final class BreakIteratorBenchmark extends SimpleBenchmark {
+
+ public static enum Text {
+ LIPSUM(Locale.US, "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Morbi mollis consequat nisl non pharetra. Praesent pretium vehicula odio sed ultrices. Aenean a felis libero. Vivamus sed commodo nibh. Pellentesque turpis lectus, euismod vel ante nec, cursus posuere orci. Suspendisse velit neque, fermentum luctus ultrices in, ultrices vitae arcu. Duis tincidunt cursus lorem. Nam ultricies accumsan quam vitae imperdiet. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Quisque aliquet pretium nisi, eget laoreet enim molestie sit amet. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos.\nNam dapibus aliquam lacus ac suscipit. Proin in nibh sit amet purus congue laoreet eget quis nisl. Morbi gravida dignissim justo, a venenatis ante pulvinar at. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Proin ultrices vestibulum dui, vel aliquam lacus aliquam quis. Duis fringilla sapien ac lacus egestas, vel adipiscing elit euismod. Donec non tellus odio. Donec gravida eu massa ac feugiat. Aliquam erat volutpat. Praesent id adipiscing metus, nec laoreet enim. Aliquam vitae posuere turpis. Mauris ac pharetra sem. In at placerat tortor. Vivamus ac vehicula neque. Cras volutpat ullamcorper massa et varius. Praesent sagittis neque vitae nulla euismod pharetra.\nSed placerat sapien non molestie sollicitudin. Nullam sit amet dictum quam. Etiam tincidunt tortor vel pretium vehicula. Praesent fringilla ipsum vel velit luctus dignissim. Nulla massa ligula, mattis in enim et, mattis lacinia odio. Suspendisse tristique urna a orci commodo tempor. Duis lacinia egestas arcu a sollicitudin.\nIn ac feugiat lacus. Nunc fermentum eu est at tristique. Pellentesque quis ligula et orci placerat lacinia. Maecenas quis mauris diam. Etiam mi ipsum, tempus in purus quis, euismod faucibus orci. Nulla facilisi. Praesent sit amet sapien vel elit porta adipiscing. Phasellus sit amet volutpat diam.\nProin bibendum elit non lacus pharetra, quis eleifend tellus placerat. Nulla facilisi. Maecenas ante diam, pellentesque mattis mattis in, porta ut lorem. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Nunc interdum tristique metus, in scelerisque odio fermentum eget. Cras nec venenatis lacus. Aenean euismod eget metus quis molestie. Cras tincidunt dolor ut massa ornare, in elementum lacus auctor. Cras sodales nisl lacus, id ultrices ligula varius at. Sed tristique sit amet tellus vel mollis. Sed sed sollicitudin quam. Sed sed adipiscing risus, et dictum orci. Cras tempor pellentesque turpis et tempus."),
+ LONGPARA(Locale.US, "During dinner, Mr. Bennet scarcely spoke at all; but when the servants were withdrawn, he thought it time to have some conversation with his guest, and therefore started a subject in which he expected him to shine, by observing that he seemed very fortunate in his patroness. Lady Catherine de Bourgh's attention to his wishes, and consideration for his comfort, appeared very remarkable. Mr. Bennet could not have chosen better. Mr. Collins was eloquent in her praise. The subject elevated him to more than usual solemnity of manner, and with a most important aspect he protested that \"he had never in his life witnessed such behaviour in a person of rank--such affability and condescension, as he had himself experienced from Lady Catherine. She had been graciously pleased to approve of both of the discourses which he had already had the honour of preaching before her. She had also asked him twice to dine at Rosings, and had sent for him only the Saturday before, to make up her pool of quadrille in the evening. Lady Catherine was reckoned proud by many people he knew, but _he_ had never seen anything but affability in her. She had always spoken to him as she would to any other gentleman; she made not the smallest objection to his joining in the society of the neighbourhood nor to his leaving the parish occasionally for a week or two, to visit his relations. She had even condescended to advise him to marry as soon as he could, provided he chose with discretion; and had once paid him a visit in his humble parsonage, where she had perfectly approved all the alterations he had been making, and had even vouchsafed to suggest some herself--some shelves in the closet up stairs.\""),
+ GERMAN(Locale.GERMANY, "Aber dieser Freiheit setzte endlich der Winter ein Ziel. Draußen auf den Feldern und den hohen Bergen lag der Schnee und Peter wäre in seinem dünnen Leinwandjäckchen bald erfroren. Es war also seine einzige Freude, hinaus vor die Hütte zu treten und den Sperlingen Brotkrümchen zu streuen, was er sich jedesmal an seinem Frühstück absparte. Wenn nun die Vögel so lustig zwitscherten und um ihn herumflogen, da klopfte ihm das Herz vor Lust, und oft gab er ihnen sein ganzes Stück Schwarzbrot, ohne daran zu denken, daß er dafür alsdann selbst hungern müsse."),
+ THAI(Locale.forLanguageTag("th-TH"), "เป็นสำเนียงทางการของภาษาไทย เดิมทีเป็นการผสมผสานกันระหว่างสำเนียงอยุธยาและชาวไทยเชื้อสายจีนรุ่นหลังที่พูดไทยแทนกลุ่มภาษาจีน ลักษณะเด่นคือมีการออกเสียงที่ชัดเจนและแข็งกระด้างซึ่งได้รับอิทธิพลจากภาษาแต้จิ๋ว การออกเสียงพยัญชนะ สระ การผันวรรณยุกต์ที่ในภาษาไทยมาตรฐาน มาจากสำเนียงถิ่นนี้ในขณะที่ภาษาไทยสำเนียงอื่นล้วนเหน่อทั้งสิ้น คำศัพท์ที่ใช้ในสำเนียงกรุงเทพจำนวนมากได้รับมาจากกลุ่มภาษาจีนเช่นคำว่า โป๊, เฮ็ง, อาหมวย, อาซิ่ม ซึ่งมาจากภาษาแต้จิ๋ว และจากภาษาจีนเช่น ถู(涂), ชิ่ว(去 อ่านว่า\"ชู่\") และคำว่า ทาย(猜 อ่านว่า \"ชาย\") เป็นต้น เนื่องจากสำเนียงกรุงเทพได้รับอิทธิพลมาจากภาษาจีนดังนั้นตัวอักษร \"ร\" มักออกเสียงเหมารวมเป็น \"ล\" หรือคำควบกล่ำบางคำถูกละทิ้งไปด้วยเช่น รู้ เป็น ลู้, เรื่อง เป็น เลื่อง หรือ ประเทศ เป็น ปะเทศ เป็นต้นสร้างความลำบากให้แก่ต่างชาติที่ต้องการเรียนภาษาไทย แต่อย่างไรก็ตามผู้ที่พูดสำเนียงถิ่นนี้ก็สามารถออกอักขระภาษาไทยตามมาตรฐานได้อย่างถูกต้องเพียงแต่มักเผลอไม่ค่อยออกเสียง"),
+ THAI2(Locale.forLanguageTag("th-TH"), "this is the word browser in Thai: เบราว์เซอร์"),
+ TABS(Locale.US, "one\t\t\t\t\t\t\t\t\t\t\t\t\t\ttwo\n"),
+ ACCENT(Locale.US, "e\u0301\u00e9\nwhich is:\n\"e\\u0301\\u00e9\""),
+ EMOJI(Locale.US, ">>\ud83d\ude01<<\nwhich is:\n\">>\\ud83d\\ude01<<\""),
+ SPACES(Locale.US, " leading spaces and trailing ones too "),
+ EMPTY(Locale.US, ""),
+ NEWLINE(Locale.US, "\\n:\n"),
+ BIDI(Locale.forLanguageTag("he-IL"), "Sarah שרה is spelled sin ש resh ר heh ה from right to left.");
+
+ final Locale locale;
+ final String text;
+
+ Text(Locale locale, String text) {
+ this.text = text;
+ this.locale = locale;
+ }
+ }
+
+ @Param private Text text;
+
+ public void timeBreakIterator(int nreps) {
+ for (int i = 0; i < nreps; ++i) {
+ BreakIterator it = BreakIterator.getLineInstance(text.locale);
+ it.setText(text.text);
+
+ while (it.next() != BreakIterator.DONE) {
+ }
+ }
+ }
+
+ public void timeIcuBreakIterator(int nreps) {
+ for (int i = 0; i < nreps; ++i) {
+ android.icu.text.BreakIterator it =
+ android.icu.text.BreakIterator.getLineInstance(text.locale);
+ it.setText(text.text);
+
+ while (it.next() != android.icu.text.BreakIterator.DONE) {
+ }
+ }
+ }
+}
diff --git a/benchmarks/src/benchmarks/regression/CollectionsBenchmark.java b/benchmarks/src/benchmarks/regression/CollectionsBenchmark.java
new file mode 100644
index 0000000..18b969a
--- /dev/null
+++ b/benchmarks/src/benchmarks/regression/CollectionsBenchmark.java
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package benchmarks.regression;
+
+import com.google.caliper.Param;
+import com.google.caliper.SimpleBenchmark;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+import java.util.Random;
+import java.util.Vector;
+
+public class CollectionsBenchmark extends SimpleBenchmark {
+ @Param({"4", "16", "64", "256", "1024"})
+ private int arrayListLength;
+
+ public static Comparator<Integer> REVERSE = new Comparator<Integer>() {
+ @Override
+ public int compare(Integer lhs, Integer rhs) {
+ int lhsAsInt = lhs.intValue();
+ int rhsAsInt = rhs.intValue();
+ return rhsAsInt < lhsAsInt ? -1 : (lhsAsInt == rhsAsInt ? 0 : 1);
+ }
+ };
+
+
+ public void timeSort_arrayList(int nreps) throws Exception {
+ List<Integer> input = buildList(arrayListLength, ArrayList.class);
+ for (int i = 0; i < nreps; ++i) {
+ Collections.sort(input);
+ }
+ }
+
+ public void timeSortWithComparator_arrayList(int nreps) throws Exception {
+ List<Integer> input = buildList(arrayListLength, ArrayList.class);
+ for (int i = 0; i < nreps; ++i) {
+ Collections.sort(input, REVERSE);
+ }
+ }
+
+ public void timeSort_vector(int nreps) throws Exception {
+ List<Integer> input = buildList(arrayListLength, Vector.class);
+ for (int i = 0; i < nreps; ++i) {
+ Collections.sort(input);
+ }
+ }
+
+ public void timeSortWithComparator_vector(int nreps) throws Exception {
+ List<Integer> input = buildList(arrayListLength, Vector.class);
+ for (int i = 0; i < nreps; ++i) {
+ Collections.sort(input, REVERSE);
+ }
+ }
+
+ private static <T extends List<Integer>> List<Integer> buildList(
+ int arrayListLength, Class<T> listClass) throws Exception {
+ Random random = new Random();
+ random.setSeed(0);
+ List<Integer> list = listClass.newInstance();
+ for (int i = 0; i < arrayListLength; ++i) {
+ list.add(random.nextInt());
+ }
+ return list;
+ }
+}
diff --git a/benchmarks/src/benchmarks/regression/DateIntervalFormatBenchmark.java b/benchmarks/src/benchmarks/regression/DateIntervalFormatBenchmark.java
index 02d8f97..e904b4d 100644
--- a/benchmarks/src/benchmarks/regression/DateIntervalFormatBenchmark.java
+++ b/benchmarks/src/benchmarks/regression/DateIntervalFormatBenchmark.java
@@ -18,39 +18,41 @@ package benchmarks.regression;
import com.google.caliper.SimpleBenchmark;
-import java.util.Locale;
-import java.util.TimeZone;
+import android.icu.util.ULocale;
+import android.icu.util.TimeZone;
-import static libcore.icu.DateIntervalFormat.*;
+import libcore.icu.DateIntervalFormat;
+
+import static libcore.icu.DateUtilsBridge.*;
public class DateIntervalFormatBenchmark extends SimpleBenchmark {
public void timeDateIntervalFormat_formatDateRange_DATE(int reps) throws Exception {
- Locale l = Locale.US;
+ ULocale l = ULocale.US;
TimeZone utc = TimeZone.getTimeZone("UTC");
int flags = FORMAT_SHOW_DATE | FORMAT_SHOW_WEEKDAY;
for (int rep = 0; rep < reps; ++rep) {
- formatDateRange(l, utc, 0L, 0L, flags);
+ DateIntervalFormat.formatDateRange(l, utc, 0L, 0L, flags);
}
}
public void timeDateIntervalFormat_formatDateRange_TIME(int reps) throws Exception {
- Locale l = Locale.US;
+ ULocale l = ULocale.US;
TimeZone utc = TimeZone.getTimeZone("UTC");
int flags = FORMAT_SHOW_TIME | FORMAT_24HOUR;
for (int rep = 0; rep < reps; ++rep) {
- formatDateRange(l, utc, 0L, 0L, flags);
+ DateIntervalFormat.formatDateRange(l, utc, 0L, 0L, flags);
}
}
public void timeDateIntervalFormat_formatDateRange_DATE_TIME(int reps) throws Exception {
- Locale l = Locale.US;
+ ULocale l = ULocale.US;
TimeZone utc = TimeZone.getTimeZone("UTC");
int flags = FORMAT_SHOW_DATE | FORMAT_SHOW_WEEKDAY | FORMAT_SHOW_TIME | FORMAT_24HOUR;
for (int rep = 0; rep < reps; ++rep) {
- formatDateRange(l, utc, 0L, 0L, flags);
+ DateIntervalFormat.formatDateRange(l, utc, 0L, 0L, flags);
}
}
}
diff --git a/benchmarks/src/benchmarks/regression/ProviderBenchmark.java b/benchmarks/src/benchmarks/regression/ProviderBenchmark.java
new file mode 100644
index 0000000..649aa01
--- /dev/null
+++ b/benchmarks/src/benchmarks/regression/ProviderBenchmark.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package benchmarks.regression;
+
+import java.security.Provider;
+import java.security.Security;
+import javax.crypto.Cipher;
+
+import com.google.caliper.Param;
+import com.google.caliper.SimpleBenchmark;
+import javax.net.ssl.SSLSocketFactory;
+
+public class ProviderBenchmark extends SimpleBenchmark {
+ public void timeStableProviders(int reps) throws Exception {
+ for (int i = 0; i < reps; ++i) {
+ Cipher c = Cipher.getInstance("RSA");
+ }
+ }
+
+ public void timeWithNewProvider(int reps) throws Exception {
+ for (int i = 0; i < reps; ++i) {
+ Security.addProvider(new MockProvider());
+ try {
+ Cipher c = Cipher.getInstance("RSA");
+ } finally {
+ Security.removeProvider("Mock");
+ }
+ }
+ }
+
+ private static class MockProvider extends Provider {
+ public MockProvider() {
+ super("Mock", 1.0, "Mock me!");
+ }
+ }
+}
diff --git a/benchmarks/src/benchmarks/regression/ReflectionBenchmark.java b/benchmarks/src/benchmarks/regression/ReflectionBenchmark.java
index f8f3c93..fcb2636 100644
--- a/benchmarks/src/benchmarks/regression/ReflectionBenchmark.java
+++ b/benchmarks/src/benchmarks/regression/ReflectionBenchmark.java
@@ -156,6 +156,13 @@ public class ReflectionBenchmark extends SimpleBenchmark {
}
}
+ public void timeClass_classNewInstance(int reps) throws Exception {
+ Class<?> klass = C.class;
+ for (int rep = 0; rep < reps; ++rep) {
+ klass.newInstance();
+ }
+ }
+
public void timeGetInstanceField(int reps) throws Exception {
for (int rep = 0; rep < reps; ++rep) {
// The field here (and in timeGetStaticField) were chosen to be
diff --git a/benchmarks/src/benchmarks/regression/RelativeDateTimeFormatterBenchmark.java b/benchmarks/src/benchmarks/regression/RelativeDateTimeFormatterBenchmark.java
new file mode 100644
index 0000000..ea2cf4a
--- /dev/null
+++ b/benchmarks/src/benchmarks/regression/RelativeDateTimeFormatterBenchmark.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package benchmarks.regression;
+
+import com.google.caliper.SimpleBenchmark;
+
+import java.util.Locale;
+import java.util.TimeZone;
+
+import static libcore.icu.DateUtilsBridge.FORMAT_ABBREV_RELATIVE;
+import static libcore.icu.RelativeDateTimeFormatter.getRelativeDateTimeString;
+import static libcore.icu.RelativeDateTimeFormatter.getRelativeTimeSpanString;
+
+public class RelativeDateTimeFormatterBenchmark extends SimpleBenchmark {
+ public void timeRelativeDateTimeFormatter_getRelativeTimeSpanString(int reps) throws Exception {
+ Locale l = Locale.US;
+ TimeZone utc = TimeZone.getTimeZone("Europe/London");
+ int flags = 0;
+
+ for (int rep = 0; rep < reps; ++rep) {
+ getRelativeTimeSpanString(l, utc, 0L, 0L, 0L, flags);
+ }
+ }
+
+ public void timeRelativeDateTimeFormatter_getRelativeTimeSpanString_ABBREV(int reps) throws Exception {
+ Locale l = Locale.US;
+ TimeZone utc = TimeZone.getTimeZone("UTC");
+ int flags = FORMAT_ABBREV_RELATIVE;
+
+ for (int rep = 0; rep < reps; ++rep) {
+ getRelativeTimeSpanString(l, utc, 0L, 0L, 0L, flags);
+ }
+ }
+
+ public void timeRelativeDateTimeFormatter_getRelativeDateTimeString(int reps) throws Exception {
+ Locale l = Locale.US;
+ TimeZone utc = TimeZone.getTimeZone("UTC");
+ int flags = 0;
+
+ for (int rep = 0; rep < reps; ++rep) {
+ getRelativeDateTimeString(l, utc, 0L, 0L, 0L, 0L, flags);
+ }
+ }
+
+ public void timeRelativeDateTimeFormatter_getRelativeDateTimeString_ABBREV(int reps) throws Exception {
+ Locale l = Locale.US;
+ TimeZone utc = TimeZone.getTimeZone("America/Los_Angeles");
+ int flags = FORMAT_ABBREV_RELATIVE;
+
+ for (int rep = 0; rep < reps; ++rep) {
+ getRelativeDateTimeString(l, utc, 0L, 0L, 0L, 0L, flags);
+ }
+ }
+}
diff --git a/dalvik/src/main/java/dalvik/system/BaseDexClassLoader.java b/dalvik/src/main/java/dalvik/system/BaseDexClassLoader.java
index 6a1a493..5ef00bf 100644
--- a/dalvik/src/main/java/dalvik/system/BaseDexClassLoader.java
+++ b/dalvik/src/main/java/dalvik/system/BaseDexClassLoader.java
@@ -130,6 +130,7 @@ public class BaseDexClassLoader extends ClassLoader {
}
result.append(directory);
}
+
return result.toString();
}
diff --git a/dalvik/src/main/java/dalvik/system/CloseGuard.java b/dalvik/src/main/java/dalvik/system/CloseGuard.java
index df36867..a45ffa1 100644
--- a/dalvik/src/main/java/dalvik/system/CloseGuard.java
+++ b/dalvik/src/main/java/dalvik/system/CloseGuard.java
@@ -40,6 +40,7 @@ package dalvik.system;
*
* protected void finalize() throws Throwable {
* try {
+ * // Note that guard could be null if the constructor threw.
* if (guard != null) {
* guard.warnIfOpen();
* }
@@ -76,6 +77,7 @@ package dalvik.system;
*
* protected void finalize() throws Throwable {
* try {
+ * // Note that guard could be null if the constructor threw.
* if (guard != null) {
* guard.warnIfOpen();
* }
@@ -94,12 +96,6 @@ package dalvik.system;
* in a method, the call to {@code open} should occur just after
* resource acquisition.
*
- * <p>
- *
- * Note that the null check on {@code guard} in the finalizer is to
- * cover cases where a constructor throws an exception causing the
- * {@code guard} to be uninitialized.
- *
* @hide
*/
public final class CloseGuard {
diff --git a/dalvik/src/main/java/dalvik/system/DexFile.java b/dalvik/src/main/java/dalvik/system/DexFile.java
index 86bb531..52d5d8a 100644
--- a/dalvik/src/main/java/dalvik/system/DexFile.java
+++ b/dalvik/src/main/java/dalvik/system/DexFile.java
@@ -34,7 +34,7 @@ import libcore.io.Libcore;
* read-only by the VM.
*/
public final class DexFile {
- private long mCookie;
+ private Object mCookie;
private final String mFileName;
private final CloseGuard guard = CloseGuard.get();
@@ -175,10 +175,10 @@ public final class DexFile {
* normally should not happen
*/
public void close() throws IOException {
- if (mCookie != 0) {
+ if (mCookie != null) {
guard.close();
closeDexFile(mCookie);
- mCookie = 0;
+ mCookie = null;
}
}
@@ -219,7 +219,7 @@ public final class DexFile {
return defineClass(name, loader, mCookie, suppressed);
}
- private static Class defineClass(String name, ClassLoader loader, long cookie,
+ private static Class defineClass(String name, ClassLoader loader, Object cookie,
List<Throwable> suppressed) {
Class result = null;
try {
@@ -290,22 +290,22 @@ public final class DexFile {
* Open a DEX file. The value returned is a magic VM cookie. On
* failure, an IOException is thrown.
*/
- private static long openDexFile(String sourceName, String outputName, int flags) throws IOException {
+ private static Object openDexFile(String sourceName, String outputName, int flags) throws IOException {
// Use absolute paths to enable the use of relative paths when testing on host.
return openDexFileNative(new File(sourceName).getAbsolutePath(),
(outputName == null) ? null : new File(outputName).getAbsolutePath(),
flags);
}
- private static native void closeDexFile(long cookie);
- private static native Class defineClassNative(String name, ClassLoader loader, long cookie)
+ private static native void closeDexFile(Object cookie);
+ private static native Class defineClassNative(String name, ClassLoader loader, Object cookie)
throws ClassNotFoundException, NoClassDefFoundError;
- private static native String[] getClassNameList(long cookie);
+ private static native String[] getClassNameList(Object cookie);
/*
* Open a DEX file. The value returned is a magic VM cookie. On
* failure, an IOException is thrown.
*/
- private static native long openDexFileNative(String sourceName, String outputName, int flags);
+ private static native Object openDexFileNative(String sourceName, String outputName, int flags);
/**
* Returns true if the VM believes that the apk/jar file is out of date
@@ -318,55 +318,58 @@ public final class DexFile {
* @throws java.io.IOException if fileName is not a valid apk/jar file or
* if problems occur while parsing it.
* @throws java.lang.NullPointerException if fileName is null.
- * @throws dalvik.system.StaleDexCacheError if the optimized dex file
- * is stale but exists on a read-only partition.
*/
public static native boolean isDexOptNeeded(String fileName)
throws FileNotFoundException, IOException;
/**
- * See {@link #isDexOptNeededInternal(String, String, String, boolean)}.
+ * See {@link #getDexOptNeeded(String, String, String, boolean)}.
*
* @hide
*/
- public static final byte UP_TO_DATE = 0;
+ public static final int NO_DEXOPT_NEEDED = 0;
/**
- * See {@link #isDexOptNeededInternal(String, String, String, boolean)}.
+ * See {@link #getDexOptNeeded(String, String, String, boolean)}.
*
* @hide
*/
- public static final byte PATCHOAT_NEEDED = 1;
+ public static final int DEX2OAT_NEEDED = 1;
/**
- * See {@link #isDexOptNeededInternal(String, String, String, boolean)}.
+ * See {@link #getDexOptNeeded(String, String, String, boolean)}.
*
* @hide
*/
- public static final byte DEXOPT_NEEDED = 2;
+ public static final int PATCHOAT_NEEDED = 2;
/**
- * Returns UP_TO_DATE if the VM believes that the apk/jar file
- * is up to date, PATCHOAT_NEEDED if it believes that the file is up
- * to date but it must be relocated to match the base address offset,
- * and DEXOPT_NEEDED if it believes that it is out of date and should
- * be passed through "dexopt" again.
+ * See {@link #getDexOptNeeded(String, String, String, boolean)}.
+ *
+ * @hide
+ */
+ public static final int SELF_PATCHOAT_NEEDED = 3;
+
+ /**
+ * Returns the VM's opinion of what kind of dexopt is needed to make the
+ * apk/jar file up to date.
*
* @param fileName the absolute path to the apk/jar file to examine.
- * @return DEXOPT_NEEDED if dexopt should be called on the file,
- * PATCHOAT_NEEDED if we need to run "patchoat" on it and
- * UP_TO_DATE otherwise.
+ * @return NO_DEXOPT_NEEDED if the apk/jar is already up to date.
+ * DEX2OAT_NEEDED if dex2oat should be called on the apk/jar file.
+ * PATCHOAT_NEEDED if patchoat should be called on the apk/jar
+ * file to patch the odex file along side the apk/jar.
+ * SELF_PATCHOAT_NEEDED if selfpatchoat should be called on the
+ * apk/jar file to patch the oat file in the dalvik cache.
* @throws java.io.FileNotFoundException if fileName is not readable,
* not a file, or not present.
* @throws java.io.IOException if fileName is not a valid apk/jar file or
* if problems occur while parsing it.
* @throws java.lang.NullPointerException if fileName is null.
- * @throws dalvik.system.StaleDexCacheError if the optimized dex file
- * is stale but exists on a read-only partition.
*
* @hide
*/
- public static native byte isDexOptNeededInternal(String fileName, String pkgname,
+ public static native int getDexOptNeeded(String fileName, String pkgname,
String instructionSet, boolean defer)
throws FileNotFoundException, IOException;
}
diff --git a/dalvik/src/main/java/dalvik/system/DexPathList.java b/dalvik/src/main/java/dalvik/system/DexPathList.java
index e364e40..e25feb9 100644
--- a/dalvik/src/main/java/dalvik/system/DexPathList.java
+++ b/dalvik/src/main/java/dalvik/system/DexPathList.java
@@ -28,6 +28,7 @@ import java.util.Collections;
import java.util.Enumeration;
import java.util.List;
import java.util.zip.ZipFile;
+import java.util.zip.ZipEntry;
import libcore.io.IoUtils;
import libcore.io.Libcore;
import static android.system.OsConstants.*;
@@ -47,6 +48,7 @@ import static android.system.OsConstants.*;
*/
/*package*/ final class DexPathList {
private static final String DEX_SUFFIX = ".dex";
+ private static final String zipSeparator = "!/";
/** class definition context */
private final ClassLoader definingContext;
@@ -58,8 +60,14 @@ import static android.system.OsConstants.*;
*/
private final Element[] dexElements;
- /** List of native library directories. */
- private final File[] nativeLibraryDirectories;
+ /** List of native library path elements. */
+ private final Element[] nativeLibraryPathElements;
+
+ /** List of application native library directories. */
+ private final List<File> nativeLibraryDirectories;
+
+ /** List of system native library directories. */
+ private final List<File> systemNativeLibraryDirectories;
/**
* Exceptions thrown during creation of the dexElements list.
@@ -81,6 +89,7 @@ import static android.system.OsConstants.*;
*/
public DexPathList(ClassLoader definingContext, String dexPath,
String libraryPath, File optimizedDirectory) {
+
if (definingContext == null) {
throw new NullPointerException("definingContext == null");
}
@@ -105,27 +114,55 @@ import static android.system.OsConstants.*;
}
this.definingContext = definingContext;
+
ArrayList<IOException> suppressedExceptions = new ArrayList<IOException>();
- this.dexElements = makeDexElements(splitDexPath(dexPath), optimizedDirectory,
- suppressedExceptions);
+ // save dexPath for BaseDexClassLoader
+ this.dexElements = makePathElements(splitDexPath(dexPath), optimizedDirectory,
+ suppressedExceptions);
+
+ // Native libraries may exist in both the system and
+ // application library paths, and we use this search order:
+ //
+ // 1. This class loader's library path for application libraries (libraryPath):
+ // 1.1. Native library directories
+ // 1.2. Path to libraries in apk-files
+ // 2. The VM's library path from the system property for system libraries
+ // also known as java.library.path
+ //
+ // This order was reversed prior to Gingerbread; see http://b/2933456.
+ this.nativeLibraryDirectories = splitPaths(libraryPath, false);
+ this.systemNativeLibraryDirectories =
+ splitPaths(System.getProperty("java.library.path"), true);
+ List<File> allNativeLibraryDirectories = new ArrayList<>(nativeLibraryDirectories);
+ allNativeLibraryDirectories.addAll(systemNativeLibraryDirectories);
+
+ this.nativeLibraryPathElements = makePathElements(allNativeLibraryDirectories, null,
+ suppressedExceptions);
+
if (suppressedExceptions.size() > 0) {
this.dexElementsSuppressedExceptions =
suppressedExceptions.toArray(new IOException[suppressedExceptions.size()]);
} else {
dexElementsSuppressedExceptions = null;
}
- this.nativeLibraryDirectories = splitLibraryPath(libraryPath);
}
@Override public String toString() {
+ List<File> allNativeLibraryDirectories = new ArrayList<>(nativeLibraryDirectories);
+ allNativeLibraryDirectories.addAll(systemNativeLibraryDirectories);
+
+ File[] nativeLibraryDirectoriesArray =
+ allNativeLibraryDirectories.toArray(
+ new File[allNativeLibraryDirectories.size()]);
+
return "DexPathList[" + Arrays.toString(dexElements) +
- ",nativeLibraryDirectories=" + Arrays.toString(nativeLibraryDirectories) + "]";
+ ",nativeLibraryDirectories=" + Arrays.toString(nativeLibraryDirectoriesArray) + "]";
}
/**
* For BaseDexClassLoader.getLdLibraryPath.
*/
- public File[] getNativeLibraryDirectories() {
+ public List<File> getNativeLibraryDirectories() {
return nativeLibraryDirectories;
}
@@ -135,27 +172,8 @@ import static android.system.OsConstants.*;
* and readable files. (That is, directories are not included in the
* result.)
*/
- private static ArrayList<File> splitDexPath(String path) {
- return splitPaths(path, null, false);
- }
-
- /**
- * Splits the given library directory path string into elements
- * using the path separator ({@code File.pathSeparator}, which
- * defaults to {@code ":"} on Android, appending on the elements
- * from the system library path, and pruning out any elements that
- * do not refer to existing and readable directories.
- */
- private static File[] splitLibraryPath(String path) {
- // Native libraries may exist in both the system and
- // application library paths, and we use this search order:
- //
- // 1. this class loader's library path for application libraries
- // 2. the VM's library path from the system property for system libraries
- //
- // This order was reversed prior to Gingerbread; see http://b/2933456.
- ArrayList<File> result = splitPaths(path, System.getProperty("java.library.path"), true);
- return result.toArray(new File[result.size()]);
+ private static List<File> splitDexPath(String path) {
+ return splitPaths(path, false);
}
/**
@@ -167,56 +185,55 @@ import static android.system.OsConstants.*;
* are empty or {@code null}, or all elements get pruned out, then
* this returns a zero-element list.
*/
- private static ArrayList<File> splitPaths(String path1, String path2,
- boolean wantDirectories) {
- ArrayList<File> result = new ArrayList<File>();
-
- splitAndAdd(path1, wantDirectories, result);
- splitAndAdd(path2, wantDirectories, result);
- return result;
- }
+ private static List<File> splitPaths(String searchPath, boolean directoriesOnly) {
+ List<File> result = new ArrayList<>();
- /**
- * Helper for {@link #splitPaths}, which does the actual splitting
- * and filtering and adding to a result.
- */
- private static void splitAndAdd(String searchPath, boolean directoriesOnly,
- ArrayList<File> resultList) {
- if (searchPath == null) {
- return;
- }
- for (String path : searchPath.split(":")) {
- try {
- StructStat sb = Libcore.os.stat(path);
- if (!directoriesOnly || S_ISDIR(sb.st_mode)) {
- resultList.add(new File(path));
+ if (searchPath != null) {
+ for (String path : searchPath.split(File.pathSeparator)) {
+ if (directoriesOnly) {
+ try {
+ StructStat sb = Libcore.os.stat(path);
+ if (!S_ISDIR(sb.st_mode)) {
+ continue;
+ }
+ } catch (ErrnoException ignored) {
+ continue;
+ }
}
- } catch (ErrnoException ignored) {
+ result.add(new File(path));
}
}
+
+ return result;
}
/**
* Makes an array of dex/resource path elements, one per element of
* the given array.
*/
- private static Element[] makeDexElements(ArrayList<File> files, File optimizedDirectory,
- ArrayList<IOException> suppressedExceptions) {
- ArrayList<Element> elements = new ArrayList<Element>();
+ private static Element[] makePathElements(List<File> files, File optimizedDirectory,
+ List<IOException> suppressedExceptions) {
+ List<Element> elements = new ArrayList<>();
/*
* Open all files and load the (direct or contained) dex files
* up front.
*/
for (File file : files) {
File zip = null;
+ File dir = new File("");
DexFile dex = null;
+ String path = file.getPath();
String name = file.getName();
- if (file.isDirectory()) {
- // We support directories for looking up resources.
- // This is only useful for running libcore tests.
+ if (path.contains(zipSeparator)) {
+ String split[] = path.split(zipSeparator, 2);
+ zip = new File(split[0]);
+ dir = new File(split[1]);
+ } else if (file.isDirectory()) {
+ // We support directories for looking up resources and native libraries.
+ // Looking up resources in directories is useful for running libcore tests.
elements.add(new Element(file, true, null, null));
- } else if (file.isFile()){
+ } else if (file.isFile()) {
if (name.endsWith(DEX_SUFFIX)) {
// Raw dex file (not inside a zip/jar).
try {
@@ -245,7 +262,7 @@ import static android.system.OsConstants.*;
}
if ((zip != null) || (dex != null)) {
- elements.add(new Element(file, false, zip, dex));
+ elements.add(new Element(dir, false, zip, dex));
}
}
@@ -378,12 +395,15 @@ import static android.system.OsConstants.*;
*/
public String findLibrary(String libraryName) {
String fileName = System.mapLibraryName(libraryName);
- for (File directory : nativeLibraryDirectories) {
- String path = new File(directory, fileName).getPath();
- if (IoUtils.canOpenReadOnly(path)) {
+
+ for (Element element : nativeLibraryPathElements) {
+ String path = element.findNativeLibrary(fileName);
+
+ if (path != null) {
return path;
}
}
+
return null;
}
@@ -391,7 +411,7 @@ import static android.system.OsConstants.*;
* Element of the dex/resource file path
*/
/*package*/ static class Element {
- private final File file;
+ private final File dir;
private final boolean isDirectory;
private final File zip;
private final DexFile dexFile;
@@ -399,8 +419,8 @@ import static android.system.OsConstants.*;
private ZipFile zipFile;
private boolean initialized;
- public Element(File file, boolean isDirectory, File zip, DexFile dexFile) {
- this.file = file;
+ public Element(File dir, boolean isDirectory, File zip, DexFile dexFile) {
+ this.dir = dir;
this.isDirectory = isDirectory;
this.zip = zip;
this.dexFile = dexFile;
@@ -408,9 +428,10 @@ import static android.system.OsConstants.*;
@Override public String toString() {
if (isDirectory) {
- return "directory \"" + file + "\"";
+ return "directory \"" + dir + "\"";
} else if (zip != null) {
- return "zip file \"" + zip + "\"";
+ return "zip file \"" + zip + "\"" +
+ (dir != null && !dir.getPath().isEmpty() ? ", dir \"" + dir + "\"" : "");
} else {
return "dex file \"" + dexFile + "\"";
}
@@ -436,18 +457,51 @@ import static android.system.OsConstants.*;
* (e.g. if the file isn't actually a zip/jar
* file).
*/
- System.logE("Unable to open zip file: " + file, ioe);
+ System.logE("Unable to open zip file: " + zip, ioe);
zipFile = null;
}
}
+ /**
+ * Returns true if entry with specified path exists and not compressed.
+ *
+ * Note that ZipEntry does not provide information about offset so we
+ * cannot reliably check if entry is page-aligned. For now we are going
+ * take optimistic approach and rely on (1) if library was extracted
+ * it would have been found by the previous step (2) if library was not extracted
+ * but STORED and not page-aligned the installation of the app would have failed
+ * because of checks in PackageManagerService.
+ */
+ private boolean isZipEntryExistsAndStored(ZipFile zipFile, String path) {
+ ZipEntry entry = zipFile.getEntry(path);
+ return entry != null && entry.getMethod() == ZipEntry.STORED;
+ }
+
+ public String findNativeLibrary(String name) {
+ maybeInit();
+
+ if (isDirectory) {
+ String path = new File(dir, name).getPath();
+ if (IoUtils.canOpenReadOnly(path)) {
+ return path;
+ }
+ } else if (zipFile != null) {
+ String entryName = new File(dir, name).getPath();
+ if (isZipEntryExistsAndStored(zipFile, entryName)) {
+ return zip.getPath() + zipSeparator + entryName;
+ }
+ }
+
+ return null;
+ }
+
public URL findResource(String name) {
maybeInit();
// We support directories so we can run tests and/or legacy code
// that uses Class.getResource.
if (isDirectory) {
- File resourceFile = new File(file, name);
+ File resourceFile = new File(dir, name);
if (resourceFile.exists()) {
try {
return resourceFile.toURI().toURL();
@@ -474,7 +528,7 @@ import static android.system.OsConstants.*;
* might end up with illegal URLs for relative
* names.
*/
- return new URL("jar:" + file.toURL() + "!/" + name);
+ return new URL("jar:" + zip.toURL() + "!/" + name);
} catch (MalformedURLException ex) {
throw new RuntimeException(ex);
}
diff --git a/dalvik/src/main/java/dalvik/system/StaleDexCacheError.java b/dalvik/src/main/java/dalvik/system/StaleDexCacheError.java
deleted file mode 100644
index 8bdd86a..0000000
--- a/dalvik/src/main/java/dalvik/system/StaleDexCacheError.java
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package dalvik.system;
-
-/**
- * Is thrown when the VM determines that a DEX file's cache is out of date, and
- * that there is no way to recreate it.
- *
- * @hide
- */
-public class StaleDexCacheError extends VirtualMachineError {
- /**
- * Creates a new exception instance and initializes it with default values.
- */
- public StaleDexCacheError() {
- super();
- }
-
- /**
- * Creates a new exception instance and initializes it with a given message.
- *
- * @param detailMessage the error message
- */
- public StaleDexCacheError(String detailMessage) {
- super(detailMessage);
- }
-}
diff --git a/dalvik/src/main/java/dalvik/system/VMDebug.java b/dalvik/src/main/java/dalvik/system/VMDebug.java
index 4b606e6..59e28e2 100644
--- a/dalvik/src/main/java/dalvik/system/VMDebug.java
+++ b/dalvik/src/main/java/dalvik/system/VMDebug.java
@@ -18,6 +18,8 @@ package dalvik.system;
import java.io.FileDescriptor;
import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
/**
* Provides access to some VM-specific debug features. Though this class and
@@ -389,4 +391,57 @@ public final class VMDebug {
* @param data the array into which the stats are written.
*/
public static native void getHeapSpaceStats(long[] data);
+
+ /* Map from the names of the runtime stats supported by getRuntimeStat() to their IDs */
+ private static final HashMap<String, Integer> runtimeStatsMap = new HashMap<>();
+
+ static {
+ runtimeStatsMap.put("art.gc.gc-count", 0);
+ runtimeStatsMap.put("art.gc.gc-time", 1);
+ runtimeStatsMap.put("art.gc.bytes-allocated", 2);
+ runtimeStatsMap.put("art.gc.bytes-freed", 3);
+ runtimeStatsMap.put("art.gc.blocking-gc-count", 4);
+ runtimeStatsMap.put("art.gc.blocking-gc-time", 5);
+ runtimeStatsMap.put("art.gc.gc-count-rate-histogram", 6);
+ runtimeStatsMap.put("art.gc.blocking-gc-count-rate-histogram", 7);
+ }
+
+ /**
+ * Returns the value of a particular runtime statistic or {@code null} if no
+ * such runtime statistic exists.
+ *
+ * @param statName
+ * the name of the runtime statistic to look up.
+ * @return the value of the runtime statistic.
+ */
+ public static String getRuntimeStat(String statName) {
+ if (statName == null) {
+ throw new NullPointerException("statName == null");
+ }
+ Integer statId = runtimeStatsMap.get(statName);
+ if (statId != null) {
+ return getRuntimeStatInternal(statId);
+ }
+ return null;
+ }
+
+ /**
+ * Returns a map of the names/values of the runtime statistics
+ * that {@link #getRuntimeStat()} supports.
+ *
+ * @return a map of the names/values of the supported runtime statistics.
+ */
+ public static Map<String, String> getRuntimeStats() {
+ HashMap<String, String> map = new HashMap<>();
+ String[] values = getRuntimeStatsInternal();
+ for (String name : runtimeStatsMap.keySet()) {
+ int id = runtimeStatsMap.get(name);
+ String value = values[id];
+ map.put(name, value);
+ }
+ return map;
+ }
+
+ private static native String getRuntimeStatInternal(int statId);
+ private static native String[] getRuntimeStatsInternal();
}
diff --git a/dalvik/src/main/java/dalvik/system/ZygoteHooks.java b/dalvik/src/main/java/dalvik/system/ZygoteHooks.java
index 11ea286..134c2f4 100644
--- a/dalvik/src/main/java/dalvik/system/ZygoteHooks.java
+++ b/dalvik/src/main/java/dalvik/system/ZygoteHooks.java
@@ -29,7 +29,7 @@ public final class ZygoteHooks {
/**
* Called by the zygote prior to every fork. Each call to {@code preFork}
- * is followed by a matching call to {@link #postForkChild(int)} on the child
+ * is followed by a matching call to {@link #postForkChild(int, String)} on the child
* process and {@link #postForkCommon()} on both the parent and the child
* process. {@code postForkCommon} is called after {@code postForkChild} in
* the child process.
@@ -47,6 +47,8 @@ public final class ZygoteHooks {
*/
public void postForkChild(int debugFlags, String instructionSet) {
nativePostForkChild(token, debugFlags, instructionSet);
+
+ Math.setRandomSeedInternal(System.currentTimeMillis());
}
/**
@@ -68,13 +70,10 @@ public final class ZygoteHooks {
*/
private static void waitUntilAllThreadsStopped() {
File tasks = new File("/proc/self/task");
+ // All Java daemons are stopped already. We're just waiting for their OS counterparts to
+ // finish as well. This shouldn't take much time so spinning is ok here.
while (tasks.list().length > 1) {
- try {
- // Experimentally, booting and playing about with a stingray, I never saw us
- // go round this loop more than once with a 10ms sleep.
- Thread.sleep(10);
- } catch (InterruptedException ignored) {
- }
+ Thread.yield();
}
}
}
diff --git a/expectations/brokentests.txt b/expectations/brokentests.txt
index aa06985..0a047a2 100644
--- a/expectations/brokentests.txt
+++ b/expectations/brokentests.txt
@@ -67,7 +67,6 @@
result: EXEC_FAILED,
names: [
"org.apache.harmony.tests.java.net.Inet6AddressTest#test_getByNameLjava_lang_String",
- "org.apache.harmony.tests.java.net.InetAddressTest#test_equalsLjava_lang_Object",
"org.apache.harmony.tests.java.net.InetAddressTest#test_getByNameLjava_lang_String",
"org.apache.harmony.tests.java.net.InetAddressTest#test_isReachableLjava_net_NetworkInterfaceII_loopbackInterface"
]
@@ -91,8 +90,8 @@
},
{
description: "The ResourceBundle code under test is probably not used much on Android and needs a lot of attention.",
+ modes: [device],
bug: 13747957,
- result: EXEC_FAILED,
names: [
"org.apache.harmony.tests.java.util.ControlTest#test_needsReload_LStringLLocaleLStringLClassLoaderResourceBundleJ"
]
@@ -100,6 +99,7 @@
{
description: "Fails in CTS, passes in CoreTestRunner.",
result: EXEC_FAILED,
+ modes: [device],
names: [
"org.apache.harmony.tests.java.net.URLConnection#test_getContentEncoding",
"libcore.java.text.OldNumberFormatTest#test_parseLjava_lang_String",
@@ -151,7 +151,7 @@
},
{
description: "Causes open dex file error",
- result: EXEC_FAILED,
+ modes: [device],
names: [
"org.apache.harmony.tests.java.lang.reflect.GenericSignatureFormatErrorTest#test_signatureFormatError"
]
diff --git a/expectations/knownfailures.txt b/expectations/knownfailures.txt
index d14afdc..f5a13c6 100644
--- a/expectations/knownfailures.txt
+++ b/expectations/knownfailures.txt
@@ -4,6 +4,7 @@
[
{
description: "can't compile a pattern with negative look-behind and quantifiers with upper bounds",
+ result: EXEC_FAILED,
name: "org.apache.harmony.regex.tests.java.util.regex.PatternTest#test_bug_40103",
bug: 40103
},
@@ -76,6 +77,7 @@
{
description: "Runtime.getRuntime().traceMethodCalls(true) doesn't return on the host, fails in CTS",
bug: 3447964,
+ result: EXEC_FAILED,
name: "libcore.java.lang.OldRuntimeTest#test_traceMethodCalls"
},
{
@@ -1317,11 +1319,13 @@
{
description: "Known failure in MathTest 1^NAN should be NAN",
bug: 11669804,
+ result: EXEC_FAILED,
name: "org.apache.harmony.tests.java.lang.MathTest#test_powDD"
},
{
description: "Known failures in PropertiesTest: We don't deal with comments in store()",
bug: 11686302,
+ result: EXEC_FAILED,
names: [
"org.apache.harmony.tests.java.util.PropertiesTest#testStore_scenario0",
"org.apache.harmony.tests.java.util.PropertiesTest#testStore_scenario1",
@@ -1343,6 +1347,7 @@
{
description: "ScannerParseLargeFileBenchmark can cause a failure due to a timeout",
bug: 14865710,
+ result: EXEC_FAILED,
name: "org.apache.harmony.tests.java.util.ScannerParseLargeFileBenchmarkTest"
},
{
@@ -1419,14 +1424,6 @@
name: "com.android.org.apache.harmony.logging.tests.java.util.logging.LevelTest#testSerializationCompatibility"
},
{
- description: "java.util.logging: Tests that require java.util.logging code changes to fix.",
- bug: 13882147,
- names: [
- "com.android.org.apache.harmony.logging.tests.java.util.logging.SocketHandlerTest#testConstructor_NoProperties",
- "com.android.org.apache.harmony.logging.tests.java.util.logging.XMLFormatterTest#test_TestFileHandlerClass_constructor"
- ]
-},
-{
description: "java.util.beans: the harmony tests were broken by Android commit 19a270e90b1e992c1f6639f355ae13564c2f3a6a",
bug: 17394106,
names: [
@@ -1457,62 +1454,77 @@
name: "org.apache.harmony.tests.java.util.GregorianCalendarTest#test_computeTime"
},
{
- description: "SpdyConnection issue https://github.com/square/okhttp/issues/644 crashes the test app. Android does not provide SPDY/HTTP_2 connections by default so have been suppressed.",
- bug: 14462336,
+ description: "OkHttp tests require SOCKS 5 support. Android PlainSocketImpl implements SOCKS 4",
+ bug: 96926,
+ names: [
+ "com.squareup.okhttp.SocksProxyTest#proxy",
+ "com.squareup.okhttp.SocksProxyTest#proxySelector"
+ ]
+},
+{
+ description: "OkHttp tests that fail on Wear devices due to a lack of memory",
+ bug: 20055487,
+ names: [
+ "com.squareup.okhttp.internal.spdy.Http20Draft09Test#tooLargeDataFrame",
+ "com.squareup.okhttp.internal.spdy.Spdy3Test#tooLargeDataFrame"
+ ]
+},
+{
+ description: "libcore.java.text.DecimalFormatSymbolsTest#test_getInstance_unknown_or_invalid_locale assumes fallback to locale other than en_US_POSIX.",
+ bug: 17374604,
names: [
- "com.squareup.okhttp.ConnectionPoolTest",
- "com.squareup.okhttp.internal.spdy.SpdyConnectionTest",
- "com.squareup.okhttp.internal.http.HttpOverHttp20Draft09Test",
- "com.squareup.okhttp.internal.http.HttpOverSpdy3Test",
- "com.squareup.okhttp.internal.http.ResponseCacheAdapterTest",
- "com.squareup.okhttp.internal.http.URLConnectionTest#npnSetsProtocolHeader_SPDY_3",
- "com.squareup.okhttp.internal.http.URLConnectionTest#npnSetsProtocolHeader_HTTP_2",
- "com.squareup.okhttp.internal.http.URLConnectionTest#zeroLengthPost_SPDY_3",
- "com.squareup.okhttp.internal.http.URLConnectionTest#zeroLengthPost_HTTP_2",
- "com.squareup.okhttp.internal.http.URLConnectionTest#zeroLengthPut_SPDY_3",
- "com.squareup.okhttp.internal.http.URLConnectionTest#zeroLengthPut_HTTP_2"
+ "libcore.java.text.DecimalFormatSymbolsTest#test_getInstance_unknown_or_invalid_locale"
]
},
{
- description: "Some OkHttp tests were written before the introduction of TLS_FALLBACK_SCSV and have only been fixed for APIs used by Android",
- bug: 17962997,
+ description: "Tests failing on host - needing investigation.",
+ modes: [host],
+ bug: 18547404,
+ result: EXEC_FAILED,
names: [
- "com.squareup.okhttp.SyncApiTest#recoverFromTlsHandshakeFailure",
- "com.squareup.okhttp.AsyncApiTest#recoverFromTlsHandshakeFailure"
+ "org.apache.harmony.tests.java.util.HashMapTest#test_EntrySet"
]
},
{
- description: "JavaApiConverterTest#createOkResponse_fromJavaHttpsUrlConnection works independently but fails when run with some other test(s).",
- bug: 17962997,
- name: "com.squareup.okhttp.internal.http.JavaApiConverterTest#createOkResponse_fromJavaHttpsUrlConnection"
+ description: "Differences between glibc and bionic",
+ modes_variants: [[host, X64]],
+ bug: 18087920,
+ result: EXEC_FAILED,
+ names: [
+ "org.apache.harmony.tests.java.lang.MathTest#test_cbrt_D"
+ ]
},
{
- description: "Okhttp test hardcodes the TLS version expected.",
- bug: 14462336,
+ description: "Recursive calls to Charset.forName from within providers will overflow the stack.",
+ result: EXEC_FAILED,
names: [
- "com.squareup.okhttp.internal.http.URLConnectionTest#sslFallbackNotUsedWhenRecycledConnectionFails"
+ "org.apache.harmony.tests.java.nio.charset.CharsetTest#testForName_withProviderWithRecursiveCall"
]
},
{
- description: "The test relies on SimpleDateFormat zzz producing GMT not GMT+00:00 as it does on Android. Android issue 66136.",
- bug: 14462336,
+ description: "Zip64 tests take too long to execute and need more than 5GB of space to run.",
+ result: EXEC_FAILED,
names: [
- "com.squareup.okhttp.internal.http.HttpResponseCacheTest#setIfModifiedSince"
+ "libcore.java.util.zip.Zip64FileTest#testZip64Support_largeNumberOfEntries",
+ "libcore.java.util.zip.Zip64FileTest#testZip64Support_totalLargerThan4G",
+ "libcore.java.util.zip.Zip64FileTest#testZip64Support_hugeEntry"
]
},
{
- description: "OkHttp tests that fail on Wear devices due to a lack of memory",
- bug: 20055487,
+ description: "OsTest.test_PacketSocketAddress needs CAP_NET_RAW",
+ bug: 19764047,
+ result: EXEC_FAILED,
names: [
- "com.squareup.okhttp.internal.spdy.Http20Draft09Test#tooLargeDataFrame",
- "com.squareup.okhttp.internal.spdy.Spdy3Test#tooLargeDataFrame"
+ "libcore.io.OsTest#test_PacketSocketAddress"
]
},
{
- description: "libcore.java.text.DecimalFormatSymbolsTest#test_getInstance_unknown_or_invalid_locale assumes fallback to locale other than en_US_POSIX.",
- bug: 17374604,
+ description: "Need to rewrite tests for the client-side of renegotiation",
+ bug: 21876068,
+ result: EXEC_FAILED,
names: [
- "libcore.java.text.DecimalFormatSymbolsTest#test_getInstance_unknown_or_invalid_locale"
+ "com.android.org.conscrypt.NativeCryptoTest#test_SSL_renegotiate",
+ "com.android.org.conscrypt.NativeCryptoTest#test_SSL_do_handshake_clientCertificateRequested_throws_after_renegotiate"
]
}
]
diff --git a/expectations/taggedtests.txt b/expectations/taggedtests.txt
index aa220d0..cc2a4d6 100644
--- a/expectations/taggedtests.txt
+++ b/expectations/taggedtests.txt
@@ -37,6 +37,7 @@
"java.util.zip.LargeZip",
"java.util.zip.ZipFile.LargeZipFile",
"java.util.zip.ZipFile.ManyEntries",
+ "libcore.java.lang.SystemTest_testArrayCopyConcurrentModification",
"sun.nio.cs.FindOneCharEncoderBugs",
"sun.nio.cs.SurrogateGB18030Test"
],
diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/java/io/FileTest.java b/harmony-tests/src/test/java/org/apache/harmony/tests/java/io/FileTest.java
index 5cc88f4..77812ed 100644
--- a/harmony-tests/src/test/java/org/apache/harmony/tests/java/io/FileTest.java
+++ b/harmony-tests/src/test/java/org/apache/harmony/tests/java/io/FileTest.java
@@ -227,8 +227,8 @@ public class FileTest extends TestCase {
assertEquals("wrong result 4", ref1.getPath(), file4.getPath());
}
- File ref2 = new File("/lib/content-types.properties");
- File file5 = new File("/", "lib/content-types.properties");
+ File ref2 = new File("/lib/test_112270.properties");
+ File file5 = new File("/", "lib/test_112270.properties");
assertEquals("wrong result 5", ref2.getPath(), file5.getPath());
}
diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/java/lang/ProcessTest.java b/harmony-tests/src/test/java/org/apache/harmony/tests/java/lang/ProcessTest.java
index b87105b..c7a6e71 100644
--- a/harmony-tests/src/test/java/org/apache/harmony/tests/java/lang/ProcessTest.java
+++ b/harmony-tests/src/test/java/org/apache/harmony/tests/java/lang/ProcessTest.java
@@ -22,9 +22,10 @@ import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
+import libcore.io.Libcore;
public class ProcessTest extends junit.framework.TestCase {
-
+ // Test that failures to exec don't leave zombies lying around.
public void test_55017() throws Exception {
ArrayList<Process> children = new ArrayList<Process>();
for (int i = 0; i < 256; ++i) {
@@ -36,13 +37,15 @@ public class ProcessTest extends junit.framework.TestCase {
}
assertEquals(0, children.size());
+ String pid = Integer.toString(Libcore.os.getpid());
boolean onDevice = new File("/system/bin").exists();
- String[] psCommand = onDevice ? new String[] { "ps" } : new String[] { "ps", "s" };
+ String[] psCommand = onDevice ? new String[] { "ps", "--ppid", pid }
+ : new String[] { "ps", "S", "--ppid", pid };
Process ps = Runtime.getRuntime().exec(psCommand, null, null);
int zombieCount = 0;
for (String line : readAndCloseStream(ps.getInputStream()).split("\n")) {
if (line.contains(" Z ") || line.contains(" Z+ ")) {
- ++zombieCount;
+ ++zombieCount;
}
}
assertEquals(0, zombieCount);
@@ -86,7 +89,7 @@ public class ProcessTest extends junit.framework.TestCase {
assertEquals("", received);
String stderr = readAndCloseStream(p.getErrorStream());
- assertTrue(stderr, stderr.contains("unrecognized option") || stderr.contains("invalid option"));
+ assertTrue(stderr, stderr.contains("no-such-option"));
p.waitFor();
p.destroy();
diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/java/lang/ref/ReferenceQueueTest.java b/harmony-tests/src/test/java/org/apache/harmony/tests/java/lang/ref/ReferenceQueueTest.java
index 75a5218..e010116 100644
--- a/harmony-tests/src/test/java/org/apache/harmony/tests/java/lang/ref/ReferenceQueueTest.java
+++ b/harmony-tests/src/test/java/org/apache/harmony/tests/java/lang/ref/ReferenceQueueTest.java
@@ -22,6 +22,7 @@ import java.lang.ref.Reference;
import java.lang.ref.ReferenceQueue;
import java.lang.ref.SoftReference;
import java.lang.ref.WeakReference;
+import java.util.concurrent.CountDownLatch;
import libcore.java.lang.ref.FinalizationTester;
public class ReferenceQueueTest extends junit.framework.TestCase {
@@ -198,27 +199,29 @@ public class ReferenceQueueTest extends junit.framework.TestCase {
assertNull(rq.poll());
class RemoveThread extends Thread {
+ public final CountDownLatch inBlock = new CountDownLatch(1);
+ public final CountDownLatch outOfBlock = new CountDownLatch(1);
public void run() {
try {
+ inBlock.countDown();
rq.remove(1000L);
} catch(InterruptedException ie) {
isThrown = true;
}
+ outOfBlock.countDown();
}
}
RemoveThread rt = new RemoveThread();
rt.start();
try {
+ rt.inBlock.await();
+ // Try to be inside of rq.remove(1000L) if possible.
Thread.sleep(10);
- } catch(InterruptedException ie) {
-
- }
+ } catch(InterruptedException ie) {}
rt.interrupt();
try {
- Thread.sleep(10);
- } catch(InterruptedException ie) {
-
- }
+ rt.outOfBlock.await();
+ } catch(InterruptedException ie) {}
assertTrue(isThrown);
assertNull(rq.poll());
diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/java/net/DatagramSocketTest.java b/harmony-tests/src/test/java/org/apache/harmony/tests/java/net/DatagramSocketTest.java
index e585b14..d9f3d91 100644
--- a/harmony-tests/src/test/java/org/apache/harmony/tests/java/net/DatagramSocketTest.java
+++ b/harmony-tests/src/test/java/org/apache/harmony/tests/java/net/DatagramSocketTest.java
@@ -745,12 +745,13 @@ public class DatagramSocketTest extends junit.framework.TestCase {
public void test_getLocalSocketAddress_ANY() throws Exception {
DatagramSocket s = new DatagramSocket(0);
- try {
- assertTrue("ANY address not IPv6: " + s.getLocalSocketAddress(),
- ((InetSocketAddress) s.getLocalSocketAddress()).getAddress() instanceof Inet6Address);
- } finally {
- s.close();
- }
+ assertEquals("ANY address not IPv6: " + s.getLocalSocketAddress(),
+ Inet6Address.ANY, s.getLocalAddress());
+ s.close();
+ s = new DatagramSocket(0, null);
+ assertEquals(Inet6Address.ANY, s.getLocalAddress());
+ assertFalse(0 == s.getLocalPort());
+ s.close();
}
public void test_setReuseAddressZ() throws Exception {
diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/java/net/InetAddressTest.java b/harmony-tests/src/test/java/org/apache/harmony/tests/java/net/InetAddressTest.java
index 42f88c1..e5742d7 100644
--- a/harmony-tests/src/test/java/org/apache/harmony/tests/java/net/InetAddressTest.java
+++ b/harmony-tests/src/test/java/org/apache/harmony/tests/java/net/InetAddressTest.java
@@ -47,7 +47,7 @@ public class InetAddressTest extends junit.framework.TestCase {
}
public void test_equalsLjava_lang_Object() throws Exception {
- InetAddress ia1 = InetAddress.getByName("localhost");
+ InetAddress ia1 = InetAddress.getByName("ip6-localhost");
InetAddress ia2 = InetAddress.getByName("::1");
assertEquals(ia2, ia1);
}
diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/java/net/MulticastSocketTest.java b/harmony-tests/src/test/java/org/apache/harmony/tests/java/net/MulticastSocketTest.java
index b6a5861..264e004 100644
--- a/harmony-tests/src/test/java/org/apache/harmony/tests/java/net/MulticastSocketTest.java
+++ b/harmony-tests/src/test/java/org/apache/harmony/tests/java/net/MulticastSocketTest.java
@@ -922,7 +922,10 @@ public class MulticastSocketTest extends junit.framework.TestCase {
return iface.isUp()
// Typically loopback interfaces do not support multicast, but we rule them out
// explicitly anyway.
- && !iface.isLoopback() && iface.supportsMulticast()
+ && !iface.isLoopback()
+ // Point-to-point interfaces are known to cause problems. http://b/23279677
+ && !iface.isPointToPoint()
+ && iface.supportsMulticast()
&& iface.getInetAddresses().hasMoreElements();
}
diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/java/nio/DirectByteBufferTest.java b/harmony-tests/src/test/java/org/apache/harmony/tests/java/nio/DirectByteBufferTest.java
index ffdfb2c..892cd1d 100644
--- a/harmony-tests/src/test/java/org/apache/harmony/tests/java/nio/DirectByteBufferTest.java
+++ b/harmony-tests/src/test/java/org/apache/harmony/tests/java/nio/DirectByteBufferTest.java
@@ -16,6 +16,10 @@
package org.apache.harmony.tests.java.nio;
import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.nio.IntBuffer;
+import java.nio.LongBuffer;
+import java.nio.ShortBuffer;
public class DirectByteBufferTest extends ByteBufferTest {
@@ -57,4 +61,57 @@ public class DirectByteBufferTest extends ByteBufferTest {
public void testIsReadOnly() {
assertFalse(buf.isReadOnly());
}
+
+ // http://b/19692084
+ // http://b/21491780
+ public void testUnalignedReadsAndWrites() {
+ // We guarantee that the first byte of the buffer is 8 byte aligned.
+ ByteBuffer buf = ByteBuffer.allocateDirect(23);
+ // Native order is always little endian, so this forces swaps.
+ buf.order(ByteOrder.BIG_ENDIAN);
+
+ for (int i = 0; i < 8; ++i) {
+ buf.position(i);
+
+ // 2 byte swaps.
+ ShortBuffer shortBuf = buf.asShortBuffer();
+ short[] shortArray = new short[] { 42, 24 };
+
+ // Write.
+ shortBuf.put(shortArray);
+ // Read
+ shortBuf.flip();
+ shortBuf.get(shortArray);
+ // Assert Equality
+ assertEquals(42, shortArray[0]);
+ assertEquals(24, shortArray[1]);
+
+ buf.position(i);
+ // 4 byte swaps.
+ IntBuffer intBuf = buf.asIntBuffer();
+ int[] intArray = new int[] { 967, 1983 };
+ // Write.
+ intBuf.put(intArray);
+ // Read
+ intBuf.flip();
+ intBuf.get(intArray);
+ // Assert Equality
+ assertEquals(967, intArray[0]);
+ assertEquals(1983, intArray[1]);
+
+
+ buf.position(i);
+ // 8 byte swaps.
+ LongBuffer longBuf = buf.asLongBuffer();
+ long[] longArray = new long[] { 2147484614L, 2147485823L };
+ // Write.
+ longBuf.put(longArray);
+ // Read
+ longBuf.flip();
+ longBuf.get(longArray);
+ // Assert Equality
+ assertEquals(2147484614L, longArray[0]);
+ assertEquals(2147485823L, longArray[1]);
+ }
+ }
}
diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/java/nio/charset/CharsetTest.java b/harmony-tests/src/test/java/org/apache/harmony/tests/java/nio/charset/CharsetTest.java
index 01cf40e..2cf278d 100644
--- a/harmony-tests/src/test/java/org/apache/harmony/tests/java/nio/charset/CharsetTest.java
+++ b/harmony-tests/src/test/java/org/apache/harmony/tests/java/nio/charset/CharsetTest.java
@@ -25,15 +25,14 @@ import java.nio.charset.CoderResult;
import java.nio.charset.IllegalCharsetNameException;
import java.nio.charset.spi.CharsetProvider;
import java.nio.charset.UnsupportedCharsetException;
-import java.security.Permission;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Locale;
import java.util.Set;
-import java.util.SortedMap;
import java.util.Vector;
+import libcore.java.nio.charset.SettableCharsetProvider;
import junit.framework.TestCase;
@@ -819,51 +818,94 @@ public class CharsetTest extends TestCase {
// Test the method isSupported(String) with charset supported by multiple providers.
public void testIsSupported_And_ForName_NormalProvider() throws Exception {
- assertTrue(Charset.isSupported("mockCharset10"));
- // ignore case problem in mock, intended
- assertTrue(Charset.isSupported("MockCharset11"));
- assertTrue(Charset.isSupported("MockCharset12"));
- assertTrue(Charset.isSupported("MOCKCharset10"));
- // intended case problem in mock
- assertTrue(Charset.isSupported("MOCKCharset11"));
- assertTrue(Charset.isSupported("MOCKCharset12"));
+ SettableCharsetProvider.setDelegate(new MockCharsetProvider());
+ try {
+ assertTrue(Charset.isSupported("mockCharset10"));
+ // ignore case problem in mock, intended
+ assertTrue(Charset.isSupported("MockCharset11"));
+ assertTrue(Charset.isSupported("MockCharset12"));
+ assertTrue(Charset.isSupported("MOCKCharset10"));
+ // intended case problem in mock
+ assertTrue(Charset.isSupported("MOCKCharset11"));
+ assertTrue(Charset.isSupported("MOCKCharset12"));
- assertTrue(Charset.forName("mockCharset10") instanceof MockCharset);
- assertTrue(Charset.forName("mockCharset11") instanceof MockCharset);
- assertTrue(Charset.forName("mockCharset12") instanceof MockCharset);
+ assertTrue(Charset.forName("mockCharset10") instanceof MockCharset);
+ assertTrue(Charset.forName("mockCharset11") instanceof MockCharset);
+ assertTrue(Charset.forName("mockCharset12") instanceof MockCharset);
- assertTrue(Charset.forName("mockCharset10") == charset2);
- // intended case problem in mock
- Charset.forName("mockCharset11");
- assertTrue(Charset.forName("mockCharset12") == charset2);
+ assertTrue(Charset.forName("mockCharset10") == charset2);
+ // intended case problem in mock
+ Charset.forName("mockCharset11");
+ assertTrue(Charset.forName("mockCharset12") == charset2);
+ } finally {
+ SettableCharsetProvider.clearDelegate();
+ }
}
// Test the method availableCharsets() with charset supported by multiple providers.
public void testAvailableCharsets_NormalProvider() throws Exception {
- assertTrue(Charset.availableCharsets().containsKey("mockCharset00"));
- assertTrue(Charset.availableCharsets().containsKey("MOCKCharset00"));
- assertTrue(Charset.availableCharsets().get("mockCharset00") instanceof MockCharset);
- assertTrue(Charset.availableCharsets().get("MOCKCharset00") instanceof MockCharset);
- assertFalse(Charset.availableCharsets().containsKey("mockCharset01"));
- assertFalse(Charset.availableCharsets().containsKey("mockCharset02"));
+ SettableCharsetProvider.setDelegate(new MockCharsetProvider());
+ try {
+ assertTrue(Charset.availableCharsets().containsKey("mockCharset00"));
+ assertTrue(Charset.availableCharsets().containsKey("MOCKCharset00"));
+ assertTrue(Charset.availableCharsets().get("mockCharset00") instanceof MockCharset);
+ assertTrue(Charset.availableCharsets().get("MOCKCharset00") instanceof MockCharset);
+ assertFalse(Charset.availableCharsets().containsKey("mockCharset01"));
+ assertFalse(Charset.availableCharsets().containsKey("mockCharset02"));
- assertTrue(Charset.availableCharsets().get("mockCharset10") == charset2);
- assertTrue(Charset.availableCharsets().get("MOCKCharset10") == charset2);
- assertFalse(Charset.availableCharsets().containsKey("mockCharset11"));
- assertFalse(Charset.availableCharsets().containsKey("mockCharset12"));
+ assertTrue(Charset.availableCharsets().get("mockCharset10") == charset2);
+ assertTrue(Charset.availableCharsets().get("MOCKCharset10") == charset2);
+ assertFalse(Charset.availableCharsets().containsKey("mockCharset11"));
+ assertFalse(Charset.availableCharsets().containsKey("mockCharset12"));
- assertTrue(Charset.availableCharsets().containsKey("mockCharset10"));
- assertTrue(Charset.availableCharsets().containsKey("MOCKCharset10"));
- assertTrue(Charset.availableCharsets().get("mockCharset10") == charset2);
- assertFalse(Charset.availableCharsets().containsKey("mockCharset11"));
- assertFalse(Charset.availableCharsets().containsKey("mockCharset12"));
+ assertTrue(Charset.availableCharsets().containsKey("mockCharset10"));
+ assertTrue(Charset.availableCharsets().containsKey("MOCKCharset10"));
+ assertTrue(Charset.availableCharsets().get("mockCharset10") == charset2);
+ assertFalse(Charset.availableCharsets().containsKey("mockCharset11"));
+ assertFalse(Charset.availableCharsets().containsKey("mockCharset12"));
+ } finally {
+ SettableCharsetProvider.clearDelegate();
+ }
}
// Test the method forName(String) when the charset provider supports a
// built-in charset.
public void testForName_DuplicateWithBuiltInCharset() throws Exception {
- assertFalse(Charset.forName("us-ascii") instanceof MockCharset);
- assertFalse(Charset.availableCharsets().get("us-ascii") instanceof MockCharset);
+ SettableCharsetProvider.setDelegate(new MockCharsetProviderASCII());
+ try {
+ assertFalse(Charset.forName("us-ascii") instanceof MockCharset);
+ assertFalse(Charset.availableCharsets().get("us-ascii") instanceof MockCharset);
+ } finally {
+ SettableCharsetProvider.clearDelegate();
+ }
+ }
+
+ // Fails on Android with a StackOverflowException.
+ public void testForName_withProviderWithRecursiveCall() throws Exception {
+ SettableCharsetProvider.setDelegate(new MockCharsetProviderWithRecursiveCall());
+ try {
+ Charset.forName("poop");
+ fail();
+ } catch (UnsupportedCharsetException expected) {
+ } finally {
+ SettableCharsetProvider.clearDelegate();
+ }
+ }
+
+ public static class MockCharsetProviderWithRecursiveCall extends CharsetProvider {
+ @Override
+ public Iterator<Charset> charsets() {
+ return null;
+ }
+
+ @Override
+ public Charset charsetForName(String charsetName) {
+ if (Charset.isSupported(charsetName)) {
+ return Charset.forName(charsetName);
+ }
+
+ return null;
+ }
}
public static class MockCharsetProvider extends CharsetProvider {
diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/java/text/ChoiceFormatTest.java b/harmony-tests/src/test/java/org/apache/harmony/tests/java/text/ChoiceFormatTest.java
index e4d6bd8..d52e586 100644
--- a/harmony-tests/src/test/java/org/apache/harmony/tests/java/text/ChoiceFormatTest.java
+++ b/harmony-tests/src/test/java/org/apache/harmony/tests/java/text/ChoiceFormatTest.java
@@ -21,6 +21,7 @@ import java.text.ChoiceFormat;
import java.text.FieldPosition;
import java.text.MessageFormat;
import java.text.ParsePosition;
+import java.util.Locale;
import junit.framework.TestCase;
@@ -466,4 +467,23 @@ public class ChoiceFormatTest extends TestCase {
assertEquals("GREATER_THAN_ONE", fmt.format(999999999D));
assertEquals("GREATER_THAN_ONE", fmt.format(Double.POSITIVE_INFINITY));
}
+
+ // http://b/19149384
+ public void testToPatternWithInfinities() {
+ final ChoiceFormat fmt = new ChoiceFormat(
+ "-\u221E<are negative|0<are fractions|1#is one|1.0<is 1+|\u221E<are many.");
+ assertEquals("-\u221E<are negative|0.0<are fractions|1.0#is one|1.0<is 1+|\u221E<are many.",
+ fmt.toPattern());
+ }
+
+ // http://b/19011159
+ public void testEscapedPatternWithConsecutiveQuotes() {
+ ChoiceFormat format = new ChoiceFormat("0#1'2''3'''4''''.");
+ String formatted = format.format(0);
+ assertEquals("12'3'4''.", formatted);
+
+ format = new ChoiceFormat("0#1'2''3'''''4''''.");
+ formatted = format.format(0);
+ assertEquals("12'3''4''.", formatted);
+ }
}
diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/java/text/MessageFormatTest.java b/harmony-tests/src/test/java/org/apache/harmony/tests/java/text/MessageFormatTest.java
index 4f99a0f..e666c97 100644
--- a/harmony-tests/src/test/java/org/apache/harmony/tests/java/text/MessageFormatTest.java
+++ b/harmony-tests/src/test/java/org/apache/harmony/tests/java/text/MessageFormatTest.java
@@ -953,4 +953,12 @@ public class MessageFormatTest extends TestCase {
String res = MessageFormat.format("bgcolor=\"{10}\"", messageArgs);
assertEquals(res, "bgcolor=\"example10\"");
}
+
+ // http://b/19011159
+ public void test19011159() {
+ final String pattern = "ab{0,choice,0#1'2''3'''4''''.}yz";
+ final MessageFormat format = new MessageFormat(pattern, Locale.ENGLISH);
+ final Object[] zero0 = new Object[] { 0 };
+ assertEquals("ab12'3'4''.yz", format.format(zero0));
+ }
}
diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/CurrencyTest.java b/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/CurrencyTest.java
index 07256e4..a32845c 100644
--- a/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/CurrencyTest.java
+++ b/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/CurrencyTest.java
@@ -154,7 +154,7 @@ public class CurrencyTest extends junit.framework.TestCase {
// BEGIN android-changed
assertEquals("currK.getSymbol()", "\u20a9", currK.getSymbol());
assertEquals("currI.getSymbol()", "IEP", currI.getSymbol());
- assertEquals("currUS.getSymbol()", "$", currUS.getSymbol());
+ assertEquals("currUS.getSymbol()", "US$", currUS.getSymbol());
// END android-changed
// Test what happens if the default is an invalid locale, one with the country Korea (KR)
@@ -220,7 +220,7 @@ public class CurrencyTest extends junit.framework.TestCase {
// \u00a5 and \uffe5 are actually the same symbol, just different code points.
// But the RI returns the \uffe5 and Android returns those with \u00a5
String[] yen = new String[] {"JPY", "\u00a5", "\u00a5JP", "JP\u00a5", "\uffe5", "\uffe5JP", "JP\uffe5"};
- String[] dollar = new String[] {"USD", "$", "US$", "$US"};
+ String[] dollar = new String[] {"USD", "$", "US$", "$US", "$ US"};
// BEGIN android-changed
// Starting CLDR 1.7 release, currency symbol for CAD changed to CA$ in some locales such as ja.
String[] cDollar = new String[] {"CA$", "CAD", "$", "Can$", "$CA"};
diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/EnumMapTest.java b/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/EnumMapTest.java
index 2a37a18..676e373 100644
--- a/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/EnumMapTest.java
+++ b/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/EnumMapTest.java
@@ -233,6 +233,17 @@ public class EnumMapTest extends TestCase {
}
}
+ @SuppressWarnings("unchecked")
+ public void testConstructor_badMapArg() {
+ HashMap badMap = new HashMap();
+ badMap.put("NotAnEnum", "Value");
+ try {
+ new EnumMap<Color, String>(badMap);
+ fail();
+ } catch (ClassCastException expected) {
+ }
+ }
+
/**
* java.util.EnumMap#clear()
*/
diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/javax/net/ServerSocketFactoryTest.java b/harmony-tests/src/test/java/org/apache/harmony/tests/javax/net/ServerSocketFactoryTest.java
index 34d7aed..ae4236c 100644
--- a/harmony-tests/src/test/java/org/apache/harmony/tests/javax/net/ServerSocketFactoryTest.java
+++ b/harmony-tests/src/test/java/org/apache/harmony/tests/javax/net/ServerSocketFactoryTest.java
@@ -20,7 +20,7 @@
* @version $Revision$
*/
-package tests.api.javax.net;
+package org.apache.harmony.tests.javax.net;
import java.io.IOException;
import java.net.InetAddress;
diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/javax/net/SocketFactoryTest.java b/harmony-tests/src/test/java/org/apache/harmony/tests/javax/net/SocketFactoryTest.java
index d566ee3..649be09 100644
--- a/harmony-tests/src/test/java/org/apache/harmony/tests/javax/net/SocketFactoryTest.java
+++ b/harmony-tests/src/test/java/org/apache/harmony/tests/javax/net/SocketFactoryTest.java
@@ -20,7 +20,7 @@
* @version $Revision$
*/
-package tests.api.javax.net;
+package org.apache.harmony.tests.javax.net;
import java.io.IOException;
import java.net.InetAddress;
diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/javax/net/ssl/CertPathTrustManagerParametersTest.java b/harmony-tests/src/test/java/org/apache/harmony/tests/javax/net/ssl/CertPathTrustManagerParametersTest.java
index 41407e8..0951bce 100644
--- a/harmony-tests/src/test/java/org/apache/harmony/tests/javax/net/ssl/CertPathTrustManagerParametersTest.java
+++ b/harmony-tests/src/test/java/org/apache/harmony/tests/javax/net/ssl/CertPathTrustManagerParametersTest.java
@@ -15,7 +15,7 @@
* limitations under the License.
*/
-package tests.api.javax.net.ssl;
+package org.apache.harmony.tests.javax.net.ssl;
import java.security.cert.CertPathParameters;
import javax.net.ssl.CertPathTrustManagerParameters;
diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/javax/net/ssl/CertificatesToPlayWith.java b/harmony-tests/src/test/java/org/apache/harmony/tests/javax/net/ssl/CertificatesToPlayWith.java
index 5bb6f06..9e2ea8d 100644
--- a/harmony-tests/src/test/java/org/apache/harmony/tests/javax/net/ssl/CertificatesToPlayWith.java
+++ b/harmony-tests/src/test/java/org/apache/harmony/tests/javax/net/ssl/CertificatesToPlayWith.java
@@ -29,7 +29,7 @@
*
*/
-package tests.api.javax.net.ssl;
+package org.apache.harmony.tests.javax.net.ssl;
/**
* Some X509 certificates to test against.
diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/javax/net/ssl/HandshakeCompletedEventTest.java b/harmony-tests/src/test/java/org/apache/harmony/tests/javax/net/ssl/HandshakeCompletedEventTest.java
index c075cea..ec2f4f3 100644
--- a/harmony-tests/src/test/java/org/apache/harmony/tests/javax/net/ssl/HandshakeCompletedEventTest.java
+++ b/harmony-tests/src/test/java/org/apache/harmony/tests/javax/net/ssl/HandshakeCompletedEventTest.java
@@ -15,7 +15,7 @@
* limitations under the License.
*/
-package tests.api.javax.net.ssl;
+package org.apache.harmony.tests.javax.net.ssl;
import dalvik.annotation.AndroidOnly;
import java.io.ByteArrayInputStream;
diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/javax/net/ssl/HostnameVerifierTest.java b/harmony-tests/src/test/java/org/apache/harmony/tests/javax/net/ssl/HostnameVerifierTest.java
index 839f3b5..013c49b 100644
--- a/harmony-tests/src/test/java/org/apache/harmony/tests/javax/net/ssl/HostnameVerifierTest.java
+++ b/harmony-tests/src/test/java/org/apache/harmony/tests/javax/net/ssl/HostnameVerifierTest.java
@@ -15,7 +15,7 @@
* the License.
*/
-package tests.api.javax.net.ssl;
+package org.apache.harmony.tests.javax.net.ssl;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
@@ -107,7 +107,7 @@ public class HostnameVerifierTest extends TestCase implements
in = new ByteArrayInputStream(X509_WILD_FOO);
x509 = (X509Certificate) cf.generateCertificate(in);
session = new mySSLSession(new X509Certificate[] {x509});
- assertTrue(verifier.verify("foo.com", session));
+ assertFalse(verifier.verify("foo.com", session));
assertTrue(verifier.verify("www.foo.com", session));
assertTrue(verifier.verify("\u82b1\u5b50.foo.com", session));
assertFalse(verifier.verify("a.b.foo.com", session));
@@ -122,7 +122,7 @@ public class HostnameVerifierTest extends TestCase implements
x509 = (X509Certificate) cf.generateCertificate(in);
session = new mySSLSession(new X509Certificate[] {x509});
// try the foo.com variations
- assertTrue(verifier.verify("foo.com", session));
+ assertFalse(verifier.verify("foo.com", session));
assertTrue(verifier.verify("www.foo.com", session));
assertTrue(verifier.verify("\u82b1\u5b50.foo.com", session));
assertFalse(verifier.verify("a.b.foo.com", session));
@@ -282,7 +282,7 @@ public class HostnameVerifierTest extends TestCase implements
assertFalse(verifier.verify("foo.com", session));
assertTrue(verifier.verify("bar.com", session));
assertTrue(verifier.verify("a.baz.com", session));
- assertTrue(verifier.verify("baz.com", session));
+ assertFalse(verifier.verify("baz.com", session));
assertFalse(verifier.verify("a.foo.com", session));
assertFalse(verifier.verify("a.bar.com", session));
assertFalse(verifier.verify("quux.com", session));
diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/javax/net/ssl/HttpsURLConnectionTest.java b/harmony-tests/src/test/java/org/apache/harmony/tests/javax/net/ssl/HttpsURLConnectionTest.java
index e2ebdbd..f2705ea 100644
--- a/harmony-tests/src/test/java/org/apache/harmony/tests/javax/net/ssl/HttpsURLConnectionTest.java
+++ b/harmony-tests/src/test/java/org/apache/harmony/tests/javax/net/ssl/HttpsURLConnectionTest.java
@@ -16,7 +16,7 @@
*/
-package tests.api.javax.net.ssl;
+package org.apache.harmony.tests.javax.net.ssl;
import java.io.ByteArrayInputStream;
import java.net.URL;
diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/javax/net/ssl/KeyManagerFactory1Test.java b/harmony-tests/src/test/java/org/apache/harmony/tests/javax/net/ssl/KeyManagerFactory1Test.java
index b369ed9..a2d1a18 100644
--- a/harmony-tests/src/test/java/org/apache/harmony/tests/javax/net/ssl/KeyManagerFactory1Test.java
+++ b/harmony-tests/src/test/java/org/apache/harmony/tests/javax/net/ssl/KeyManagerFactory1Test.java
@@ -15,7 +15,7 @@
* limitations under the License.
*/
-package tests.api.javax.net.ssl;
+package org.apache.harmony.tests.javax.net.ssl;
import java.io.IOException;
import java.security.InvalidAlgorithmParameterException;
diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/javax/net/ssl/KeyManagerFactory2Test.java b/harmony-tests/src/test/java/org/apache/harmony/tests/javax/net/ssl/KeyManagerFactory2Test.java
index 3d44396..006d0df 100644
--- a/harmony-tests/src/test/java/org/apache/harmony/tests/javax/net/ssl/KeyManagerFactory2Test.java
+++ b/harmony-tests/src/test/java/org/apache/harmony/tests/javax/net/ssl/KeyManagerFactory2Test.java
@@ -15,7 +15,7 @@
* limitations under the License.
*/
-package tests.api.javax.net.ssl;
+package org.apache.harmony.tests.javax.net.ssl;
import java.security.InvalidAlgorithmParameterException;
import java.security.KeyStore;
diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/javax/net/ssl/KeyManagerFactorySpiTest.java b/harmony-tests/src/test/java/org/apache/harmony/tests/javax/net/ssl/KeyManagerFactorySpiTest.java
index fd44fda..fc98cbe 100644
--- a/harmony-tests/src/test/java/org/apache/harmony/tests/javax/net/ssl/KeyManagerFactorySpiTest.java
+++ b/harmony-tests/src/test/java/org/apache/harmony/tests/javax/net/ssl/KeyManagerFactorySpiTest.java
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package tests.api.javax.net.ssl;
+package org.apache.harmony.tests.javax.net.ssl;
import java.security.InvalidAlgorithmParameterException;
import java.security.KeyStore;
diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/javax/net/ssl/KeyStoreBuilderParametersTest.java b/harmony-tests/src/test/java/org/apache/harmony/tests/javax/net/ssl/KeyStoreBuilderParametersTest.java
index a2fe49c..84fecd3 100644
--- a/harmony-tests/src/test/java/org/apache/harmony/tests/javax/net/ssl/KeyStoreBuilderParametersTest.java
+++ b/harmony-tests/src/test/java/org/apache/harmony/tests/javax/net/ssl/KeyStoreBuilderParametersTest.java
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package tests.api.javax.net.ssl;
+package org.apache.harmony.tests.javax.net.ssl;
import javax.net.ssl.KeyManagerFactorySpi;
import javax.net.ssl.KeyStoreBuilderParameters;
diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/javax/net/ssl/SSLContext1Test.java b/harmony-tests/src/test/java/org/apache/harmony/tests/javax/net/ssl/SSLContext1Test.java
index ee51cc0..96168b0 100644
--- a/harmony-tests/src/test/java/org/apache/harmony/tests/javax/net/ssl/SSLContext1Test.java
+++ b/harmony-tests/src/test/java/org/apache/harmony/tests/javax/net/ssl/SSLContext1Test.java
@@ -15,7 +15,7 @@
* limitations under the License.
*/
-package tests.api.javax.net.ssl;
+package org.apache.harmony.tests.javax.net.ssl;
import java.io.FileNotFoundException;
import java.security.KeyManagementException;
diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/javax/net/ssl/SSLContext2Test.java b/harmony-tests/src/test/java/org/apache/harmony/tests/javax/net/ssl/SSLContext2Test.java
index 0881615..b35843d 100644
--- a/harmony-tests/src/test/java/org/apache/harmony/tests/javax/net/ssl/SSLContext2Test.java
+++ b/harmony-tests/src/test/java/org/apache/harmony/tests/javax/net/ssl/SSLContext2Test.java
@@ -15,7 +15,7 @@
* limitations under the License.
*/
-package tests.api.javax.net.ssl;
+package org.apache.harmony.tests.javax.net.ssl;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/javax/net/ssl/SSLContextSpiTest.java b/harmony-tests/src/test/java/org/apache/harmony/tests/javax/net/ssl/SSLContextSpiTest.java
index 45a1c14..45e9d40 100644
--- a/harmony-tests/src/test/java/org/apache/harmony/tests/javax/net/ssl/SSLContextSpiTest.java
+++ b/harmony-tests/src/test/java/org/apache/harmony/tests/javax/net/ssl/SSLContextSpiTest.java
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package tests.api.javax.net.ssl;
+package org.apache.harmony.tests.javax.net.ssl;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContextSpi;
diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/javax/net/ssl/SSLEngineResultHandshakeStatusTest.java b/harmony-tests/src/test/java/org/apache/harmony/tests/javax/net/ssl/SSLEngineResultHandshakeStatusTest.java
index 3b13673..e0e2137 100644
--- a/harmony-tests/src/test/java/org/apache/harmony/tests/javax/net/ssl/SSLEngineResultHandshakeStatusTest.java
+++ b/harmony-tests/src/test/java/org/apache/harmony/tests/javax/net/ssl/SSLEngineResultHandshakeStatusTest.java
@@ -14,7 +14,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package tests.api.javax.net.ssl;
+package org.apache.harmony.tests.javax.net.ssl;
import javax.net.ssl.SSLEngineResult;
diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/javax/net/ssl/SSLEngineResultStatusTest.java b/harmony-tests/src/test/java/org/apache/harmony/tests/javax/net/ssl/SSLEngineResultStatusTest.java
index 05c8f03..906b8b0 100644
--- a/harmony-tests/src/test/java/org/apache/harmony/tests/javax/net/ssl/SSLEngineResultStatusTest.java
+++ b/harmony-tests/src/test/java/org/apache/harmony/tests/javax/net/ssl/SSLEngineResultStatusTest.java
@@ -14,7 +14,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package tests.api.javax.net.ssl;
+package org.apache.harmony.tests.javax.net.ssl;
import javax.net.ssl.SSLEngineResult;
diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/javax/net/ssl/SSLEngineResultTest.java b/harmony-tests/src/test/java/org/apache/harmony/tests/javax/net/ssl/SSLEngineResultTest.java
index 7a2ac78..fd1d389 100644
--- a/harmony-tests/src/test/java/org/apache/harmony/tests/javax/net/ssl/SSLEngineResultTest.java
+++ b/harmony-tests/src/test/java/org/apache/harmony/tests/javax/net/ssl/SSLEngineResultTest.java
@@ -15,7 +15,7 @@
* limitations under the License.
*/
-package tests.api.javax.net.ssl;
+package org.apache.harmony.tests.javax.net.ssl;
import javax.net.ssl.SSLEngineResult;
import junit.framework.TestCase;
diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/javax/net/ssl/SSLEngineTest.java b/harmony-tests/src/test/java/org/apache/harmony/tests/javax/net/ssl/SSLEngineTest.java
index 31f5881..9360c00 100644
--- a/harmony-tests/src/test/java/org/apache/harmony/tests/javax/net/ssl/SSLEngineTest.java
+++ b/harmony-tests/src/test/java/org/apache/harmony/tests/javax/net/ssl/SSLEngineTest.java
@@ -15,7 +15,7 @@
* limitations under the License.
*/
-package tests.api.javax.net.ssl;
+package org.apache.harmony.tests.javax.net.ssl;
import java.io.IOException;
import java.nio.ByteBuffer;
@@ -36,6 +36,7 @@ import javax.net.ssl.SSLException;
import javax.net.ssl.SSLEngineResult.HandshakeStatus;
import junit.framework.TestCase;
import libcore.java.security.StandardNames;
+import libcore.javax.net.ssl.TestSSLContext;
/**
* Tests for SSLEngine class
@@ -1042,21 +1043,12 @@ public class SSLEngineTest extends TestCase {
private ByteBuffer writeBuffer;
- HandshakeHandler(boolean clientMode, SourceChannel in, SinkChannel out) throws Exception {
+ HandshakeHandler(SSLContext context, boolean clientMode, SourceChannel in, SinkChannel out)
+ throws Exception {
this.in = in;
this.out = out;
- engine = getEngine();
+ engine = context.createSSLEngine();
engine.setUseClientMode(clientMode);
- String[] cipherSuites = engine.getSupportedCipherSuites();
- Set<String> enabledSuites = new HashSet<String>();
- for (String cipherSuite : cipherSuites) {
- if (cipherSuite.contains("anon")) {
- enabledSuites.add(cipherSuite);
- }
- }
- engine.setEnabledCipherSuites((String[]) enabledSuites.toArray(
- new String[enabledSuites.size()]));
-
engine.beginHandshake();
status = engine.getHandshakeStatus();
@@ -1179,8 +1171,9 @@ public class SSLEngineTest extends TestCase {
SinkChannel serverSink = serverSendPipe.sink();
SourceChannel clientSource = serverSendPipe.source();
- clientEngine = new HandshakeHandler(true, clientSource, clientSink);
- serverEngine = new HandshakeHandler(false, serverSource, serverSink);
+ TestSSLContext context = TestSSLContext.create();
+ clientEngine = new HandshakeHandler(context.clientContext, true, clientSource, clientSink);
+ serverEngine = new HandshakeHandler(context.serverContext, false, serverSource, serverSink);
}
boolean doHandshake() throws InterruptedException {
diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/javax/net/ssl/SSLExceptionTest.java b/harmony-tests/src/test/java/org/apache/harmony/tests/javax/net/ssl/SSLExceptionTest.java
index 9b4ae35..addffd5 100644
--- a/harmony-tests/src/test/java/org/apache/harmony/tests/javax/net/ssl/SSLExceptionTest.java
+++ b/harmony-tests/src/test/java/org/apache/harmony/tests/javax/net/ssl/SSLExceptionTest.java
@@ -15,7 +15,7 @@
* limitations under the License.
*/
-package tests.api.javax.net.ssl;
+package org.apache.harmony.tests.javax.net.ssl;
import javax.net.ssl.SSLException;
diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/javax/net/ssl/SSLHandshakeExceptionTest.java b/harmony-tests/src/test/java/org/apache/harmony/tests/javax/net/ssl/SSLHandshakeExceptionTest.java
index a2d0ec5..c6770ea 100644
--- a/harmony-tests/src/test/java/org/apache/harmony/tests/javax/net/ssl/SSLHandshakeExceptionTest.java
+++ b/harmony-tests/src/test/java/org/apache/harmony/tests/javax/net/ssl/SSLHandshakeExceptionTest.java
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package tests.api.javax.net.ssl;
+package org.apache.harmony.tests.javax.net.ssl;
import javax.net.ssl.SSLHandshakeException;
diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/javax/net/ssl/SSLKeyExceptionTest.java b/harmony-tests/src/test/java/org/apache/harmony/tests/javax/net/ssl/SSLKeyExceptionTest.java
index d6ba998..961dcb2 100644
--- a/harmony-tests/src/test/java/org/apache/harmony/tests/javax/net/ssl/SSLKeyExceptionTest.java
+++ b/harmony-tests/src/test/java/org/apache/harmony/tests/javax/net/ssl/SSLKeyExceptionTest.java
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package tests.api.javax.net.ssl;
+package org.apache.harmony.tests.javax.net.ssl;
import javax.net.ssl.SSLKeyException;
diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/javax/net/ssl/SSLPeerUnverifiedExceptionTest.java b/harmony-tests/src/test/java/org/apache/harmony/tests/javax/net/ssl/SSLPeerUnverifiedExceptionTest.java
index a8b9ac4..fd74ce2 100644
--- a/harmony-tests/src/test/java/org/apache/harmony/tests/javax/net/ssl/SSLPeerUnverifiedExceptionTest.java
+++ b/harmony-tests/src/test/java/org/apache/harmony/tests/javax/net/ssl/SSLPeerUnverifiedExceptionTest.java
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package tests.api.javax.net.ssl;
+package org.apache.harmony.tests.javax.net.ssl;
import javax.net.ssl.SSLPeerUnverifiedException;
diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/javax/net/ssl/SSLProtocolExceptionTest.java b/harmony-tests/src/test/java/org/apache/harmony/tests/javax/net/ssl/SSLProtocolExceptionTest.java
index 14b562d..6763ec7 100644
--- a/harmony-tests/src/test/java/org/apache/harmony/tests/javax/net/ssl/SSLProtocolExceptionTest.java
+++ b/harmony-tests/src/test/java/org/apache/harmony/tests/javax/net/ssl/SSLProtocolExceptionTest.java
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package tests.api.javax.net.ssl;
+package org.apache.harmony.tests.javax.net.ssl;
import javax.net.ssl.SSLProtocolException;
diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/javax/net/ssl/SSLServerSocketFactoryTest.java b/harmony-tests/src/test/java/org/apache/harmony/tests/javax/net/ssl/SSLServerSocketFactoryTest.java
index 5958ecb..ea291ad 100644
--- a/harmony-tests/src/test/java/org/apache/harmony/tests/javax/net/ssl/SSLServerSocketFactoryTest.java
+++ b/harmony-tests/src/test/java/org/apache/harmony/tests/javax/net/ssl/SSLServerSocketFactoryTest.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package tests.api.javax.net.ssl;
+package org.apache.harmony.tests.javax.net.ssl;
import java.io.IOException;
import java.net.InetAddress;
diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/javax/net/ssl/SSLServerSocketTest.java b/harmony-tests/src/test/java/org/apache/harmony/tests/javax/net/ssl/SSLServerSocketTest.java
index 5086f65..5a0cf6f 100644
--- a/harmony-tests/src/test/java/org/apache/harmony/tests/javax/net/ssl/SSLServerSocketTest.java
+++ b/harmony-tests/src/test/java/org/apache/harmony/tests/javax/net/ssl/SSLServerSocketTest.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package tests.api.javax.net.ssl;
+package org.apache.harmony.tests.javax.net.ssl;
import junit.framework.TestCase;
diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/javax/net/ssl/SSLSessionBindingEventTest.java b/harmony-tests/src/test/java/org/apache/harmony/tests/javax/net/ssl/SSLSessionBindingEventTest.java
index dfccf68..ed0944d 100644
--- a/harmony-tests/src/test/java/org/apache/harmony/tests/javax/net/ssl/SSLSessionBindingEventTest.java
+++ b/harmony-tests/src/test/java/org/apache/harmony/tests/javax/net/ssl/SSLSessionBindingEventTest.java
@@ -15,7 +15,7 @@
* limitations under the License.
*/
-package tests.api.javax.net.ssl;
+package org.apache.harmony.tests.javax.net.ssl;
import java.security.Principal;
import java.security.cert.Certificate;
diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/javax/net/ssl/SSLSessionBindingListenerTest.java b/harmony-tests/src/test/java/org/apache/harmony/tests/javax/net/ssl/SSLSessionBindingListenerTest.java
index a006a83..6c597b3 100644
--- a/harmony-tests/src/test/java/org/apache/harmony/tests/javax/net/ssl/SSLSessionBindingListenerTest.java
+++ b/harmony-tests/src/test/java/org/apache/harmony/tests/javax/net/ssl/SSLSessionBindingListenerTest.java
@@ -15,7 +15,7 @@
* limitations under the License.
*/
-package tests.api.javax.net.ssl;
+package org.apache.harmony.tests.javax.net.ssl;
import javax.net.ssl.SSLServerSocket;
import javax.net.ssl.SSLServerSocketFactory;
diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/javax/net/ssl/SSLSessionContextTest.java b/harmony-tests/src/test/java/org/apache/harmony/tests/javax/net/ssl/SSLSessionContextTest.java
index aa95eb8..c0beb99 100644
--- a/harmony-tests/src/test/java/org/apache/harmony/tests/javax/net/ssl/SSLSessionContextTest.java
+++ b/harmony-tests/src/test/java/org/apache/harmony/tests/javax/net/ssl/SSLSessionContextTest.java
@@ -1,4 +1,4 @@
-package tests.api.javax.net.ssl;
+package org.apache.harmony.tests.javax.net.ssl;
import junit.framework.TestCase;
diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/javax/net/ssl/SSLSessionTest.java b/harmony-tests/src/test/java/org/apache/harmony/tests/javax/net/ssl/SSLSessionTest.java
index 2ba913d..0c0b384 100644
--- a/harmony-tests/src/test/java/org/apache/harmony/tests/javax/net/ssl/SSLSessionTest.java
+++ b/harmony-tests/src/test/java/org/apache/harmony/tests/javax/net/ssl/SSLSessionTest.java
@@ -15,7 +15,7 @@
* limitations under the License.
*/
-package tests.api.javax.net.ssl;
+package org.apache.harmony.tests.javax.net.ssl;
import libcore.java.security.StandardNames;
import java.io.ByteArrayInputStream;
@@ -38,8 +38,8 @@ import javax.net.ssl.SSLSocket;
import javax.net.ssl.TrustManager;
import junit.framework.TestCase;
import libcore.io.Base64;
-import tests.api.javax.net.ssl.HandshakeCompletedEventTest.MyHandshakeListener;
-import tests.api.javax.net.ssl.HandshakeCompletedEventTest.TestTrustManager;
+import org.apache.harmony.tests.javax.net.ssl.HandshakeCompletedEventTest.MyHandshakeListener;
+import org.apache.harmony.tests.javax.net.ssl.HandshakeCompletedEventTest.TestTrustManager;
public class SSLSessionTest extends TestCase {
diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/javax/net/ssl/SSLSocketFactoryTest.java b/harmony-tests/src/test/java/org/apache/harmony/tests/javax/net/ssl/SSLSocketFactoryTest.java
index e890032..2f456e0 100644
--- a/harmony-tests/src/test/java/org/apache/harmony/tests/javax/net/ssl/SSLSocketFactoryTest.java
+++ b/harmony-tests/src/test/java/org/apache/harmony/tests/javax/net/ssl/SSLSocketFactoryTest.java
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package tests.api.javax.net.ssl;
+package org.apache.harmony.tests.javax.net.ssl;
import java.io.IOException;
import java.net.ServerSocket;
diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/javax/net/ssl/SSLSocketTest.java b/harmony-tests/src/test/java/org/apache/harmony/tests/javax/net/ssl/SSLSocketTest.java
index 950d534..11e3142 100644
--- a/harmony-tests/src/test/java/org/apache/harmony/tests/javax/net/ssl/SSLSocketTest.java
+++ b/harmony-tests/src/test/java/org/apache/harmony/tests/javax/net/ssl/SSLSocketTest.java
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package tests.api.javax.net.ssl;
+package org.apache.harmony.tests.javax.net.ssl;
import dalvik.annotation.AndroidOnly;
import java.io.ByteArrayInputStream;
@@ -37,8 +37,8 @@ import javax.net.ssl.TrustManager;
import javax.security.cert.X509Certificate;
import junit.framework.TestCase;
import libcore.io.Base64;
-import tests.api.javax.net.ssl.HandshakeCompletedEventTest.TestTrustManager;
import libcore.java.security.StandardNames;
+import org.apache.harmony.tests.javax.net.ssl.HandshakeCompletedEventTest.TestTrustManager;
public class SSLSocketTest extends TestCase {
diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/javax/net/ssl/TrustManagerFactory1Test.java b/harmony-tests/src/test/java/org/apache/harmony/tests/javax/net/ssl/TrustManagerFactory1Test.java
index 23b24e4..9b5b929 100644
--- a/harmony-tests/src/test/java/org/apache/harmony/tests/javax/net/ssl/TrustManagerFactory1Test.java
+++ b/harmony-tests/src/test/java/org/apache/harmony/tests/javax/net/ssl/TrustManagerFactory1Test.java
@@ -15,7 +15,7 @@
* limitations under the License.
*/
-package tests.api.javax.net.ssl;
+package org.apache.harmony.tests.javax.net.ssl;
import dalvik.annotation.KnownFailure;
import java.io.IOException;
diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/javax/net/ssl/TrustManagerFactory2Test.java b/harmony-tests/src/test/java/org/apache/harmony/tests/javax/net/ssl/TrustManagerFactory2Test.java
index 0c0760f..e495419 100644
--- a/harmony-tests/src/test/java/org/apache/harmony/tests/javax/net/ssl/TrustManagerFactory2Test.java
+++ b/harmony-tests/src/test/java/org/apache/harmony/tests/javax/net/ssl/TrustManagerFactory2Test.java
@@ -15,7 +15,7 @@
* limitations under the License.
*/
-package tests.api.javax.net.ssl;
+package org.apache.harmony.tests.javax.net.ssl;
import java.security.InvalidAlgorithmParameterException;
import java.security.KeyStore;
diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/javax/net/ssl/TrustManagerFactorySpiTest.java b/harmony-tests/src/test/java/org/apache/harmony/tests/javax/net/ssl/TrustManagerFactorySpiTest.java
index 7bdeb45..7d15787 100644
--- a/harmony-tests/src/test/java/org/apache/harmony/tests/javax/net/ssl/TrustManagerFactorySpiTest.java
+++ b/harmony-tests/src/test/java/org/apache/harmony/tests/javax/net/ssl/TrustManagerFactorySpiTest.java
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package tests.api.javax.net.ssl;
+package org.apache.harmony.tests.javax.net.ssl;
import java.security.AccessController;
import java.security.InvalidAlgorithmParameterException;
diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/javax/net/ssl/X509ExtendedKeyManagerTest.java b/harmony-tests/src/test/java/org/apache/harmony/tests/javax/net/ssl/X509ExtendedKeyManagerTest.java
index 514fed8..13740af 100644
--- a/harmony-tests/src/test/java/org/apache/harmony/tests/javax/net/ssl/X509ExtendedKeyManagerTest.java
+++ b/harmony-tests/src/test/java/org/apache/harmony/tests/javax/net/ssl/X509ExtendedKeyManagerTest.java
@@ -15,7 +15,7 @@
* limitations under the License.
*/
-package tests.api.javax.net.ssl;
+package org.apache.harmony.tests.javax.net.ssl;
import java.net.Socket;
import java.security.Principal;
diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/javax/net/ssl/X509KeyManagerTest.java b/harmony-tests/src/test/java/org/apache/harmony/tests/javax/net/ssl/X509KeyManagerTest.java
index 4dddbc6..6ed67bd 100644
--- a/harmony-tests/src/test/java/org/apache/harmony/tests/javax/net/ssl/X509KeyManagerTest.java
+++ b/harmony-tests/src/test/java/org/apache/harmony/tests/javax/net/ssl/X509KeyManagerTest.java
@@ -1,4 +1,4 @@
-package tests.api.javax.net.ssl;
+package org.apache.harmony.tests.javax.net.ssl;
import java.io.ByteArrayInputStream;
import java.net.Socket;
diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/javax/net/ssl/X509TrustManagerTest.java b/harmony-tests/src/test/java/org/apache/harmony/tests/javax/net/ssl/X509TrustManagerTest.java
index ade0eca..ece0a73 100644
--- a/harmony-tests/src/test/java/org/apache/harmony/tests/javax/net/ssl/X509TrustManagerTest.java
+++ b/harmony-tests/src/test/java/org/apache/harmony/tests/javax/net/ssl/X509TrustManagerTest.java
@@ -1,4 +1,4 @@
-package tests.api.javax.net.ssl;
+package org.apache.harmony.tests.javax.net.ssl;
import java.io.ByteArrayInputStream;
import java.security.cert.CertificateException;
diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/javax/security/cert/X509CertificateTest.java b/harmony-tests/src/test/java/org/apache/harmony/tests/javax/security/cert/X509CertificateTest.java
index 64bfbb3..093e2e1 100644
--- a/harmony-tests/src/test/java/org/apache/harmony/tests/javax/security/cert/X509CertificateTest.java
+++ b/harmony-tests/src/test/java/org/apache/harmony/tests/javax/security/cert/X509CertificateTest.java
@@ -20,7 +20,7 @@
* @version $Revision$
*/
-package tests.api.javax.security.cert;
+package org.apache.harmony.tests.javax.security.cert;
import junit.framework.Test;
import junit.framework.TestCase;
@@ -39,6 +39,7 @@ import java.security.Principal;
import java.security.Provider;
import java.security.PublicKey;
import java.security.Security;
+import java.security.Signature;
import java.security.SignatureException;
import java.security.Provider.Service;
import java.security.cert.CertificateFactory;
@@ -763,16 +764,16 @@ public class X509CertificateTest extends TestCase {
}
Security.addProvider(myProvider);
- Provider[] providers = Security.getProviders("Signature.MD5withRSA");
- if (providers == null || providers.length == 0) {
- fail("no Provider for Signature.MD5withRSA");
- return;
- }
+ // Find the Provider which offers MD5withRSA for the certificate's
+ // public key.
+ Signature signature = Signature.getInstance("MD5withRSA");
+ signature.initVerify(javaxSSCert.getPublicKey());
+ Provider provider = signature.getProvider();
// self signed cert: should verify with provider
try {
javaxSSCert.verify(javaxSSCert.getPublicKey(),
- providers[0].getName());
+ provider.getName());
} catch (SignatureException e) {
fail("blu");
}
diff --git a/harmony-tests/src/test/resources/META-INF/services/java.nio.charset.spi.CharsetProvider b/harmony-tests/src/test/resources/META-INF/services/java.nio.charset.spi.CharsetProvider
deleted file mode 100644
index 9cc124a..0000000
--- a/harmony-tests/src/test/resources/META-INF/services/java.nio.charset.spi.CharsetProvider
+++ /dev/null
@@ -1,2 +0,0 @@
-org.apache.harmony.tests.java.nio.charset.CharsetTest$MockCharsetProvider
-org.apache.harmony.tests.java.nio.charset.CharsetTest$MockCharsetProviderASCII
diff --git a/include/ScopedIcuLocale.h b/include/ScopedIcuLocale.h
index 2109e03..64186e3 100644
--- a/include/ScopedIcuLocale.h
+++ b/include/ScopedIcuLocale.h
@@ -36,7 +36,7 @@ class ScopedIcuLocale {
return;
}
- mLocale = Locale::createFromName(localeName.c_str());
+ mLocale = icu::Locale::createFromName(localeName.c_str());
}
~ScopedIcuLocale() {
@@ -46,13 +46,13 @@ class ScopedIcuLocale {
return !mLocale.isBogus();
}
- Locale& locale() {
+ icu::Locale& locale() {
return mLocale;
}
private:
JNIEnv* const mEnv;
- Locale mLocale;
+ icu::Locale mLocale;
// Disallow copy and assignment.
ScopedIcuLocale(const ScopedIcuLocale&);
diff --git a/include/ScopedJavaUnicodeString.h b/include/ScopedJavaUnicodeString.h
index f6ed7ad..c1f487e 100644
--- a/include/ScopedJavaUnicodeString.h
+++ b/include/ScopedJavaUnicodeString.h
@@ -45,11 +45,11 @@ class ScopedJavaUnicodeString {
return (mString != NULL);
}
- const UnicodeString& unicodeString() const {
+ const icu::UnicodeString& unicodeString() const {
return mUnicodeString;
}
- UnicodeString& unicodeString() {
+ icu::UnicodeString& unicodeString() {
return mUnicodeString;
}
@@ -57,7 +57,7 @@ class ScopedJavaUnicodeString {
JNIEnv* mEnv;
jstring mString;
const UChar* mChars;
- UnicodeString mUnicodeString;
+ icu::UnicodeString mUnicodeString;
// Disallow copy and assignment.
ScopedJavaUnicodeString(const ScopedJavaUnicodeString&);
diff --git a/jarjar-rules.txt b/jarjar-rules.txt
new file mode 100644
index 0000000..b2da6eb
--- /dev/null
+++ b/jarjar-rules.txt
@@ -0,0 +1 @@
+rule com.ibm.icu.** android.icu.@1
diff --git a/json/src/main/java/org/json/JSONTokener.java b/json/src/main/java/org/json/JSONTokener.java
index 202e2e6..8caecc8 100644
--- a/json/src/main/java/org/json/JSONTokener.java
+++ b/json/src/main/java/org/json/JSONTokener.java
@@ -188,8 +188,6 @@ public class JSONTokener {
* not include it in the returned string.
*
* @param quote either ' or ".
- * @throws NumberFormatException if any unicode escape sequences are
- * malformed.
*/
public String nextString(char quote) throws JSONException {
/*
@@ -235,9 +233,6 @@ public class JSONTokener {
* immediately follow a backslash. The backslash '\' should have already
* been read. This supports both unicode escapes "u000A" and two-character
* escapes "\n".
- *
- * @throws NumberFormatException if any unicode escape sequences are
- * malformed.
*/
private char readEscapeCharacter() throws JSONException {
char escaped = in.charAt(pos++);
@@ -248,7 +243,11 @@ public class JSONTokener {
}
String hex = in.substring(pos, pos + 4);
pos += 4;
- return (char) Integer.parseInt(hex, 16);
+ try {
+ return (char) Integer.parseInt(hex, 16);
+ } catch (NumberFormatException nfe) {
+ throw syntaxError("Invalid escape sequence: " + hex);
+ }
case 't':
return '\t';
diff --git a/json/src/test/java/org/json/JSONObjectTest.java b/json/src/test/java/org/json/JSONObjectTest.java
index e89db94..a1b7b13 100644
--- a/json/src/test/java/org/json/JSONObjectTest.java
+++ b/json/src/test/java/org/json/JSONObjectTest.java
@@ -1029,4 +1029,13 @@ public class JSONObjectTest extends TestCase {
} catch (JSONException e) {
}
}
+
+ // https://code.google.com/p/android/issues/detail?id=103641
+ public void testInvalidUnicodeEscape() {
+ try {
+ new JSONObject("{\"q\":\"\\u\", \"r\":[]}");
+ fail();
+ } catch (JSONException expected) {
+ }
+ }
}
diff --git a/json/src/test/java/org/json/JSONTokenerTest.java b/json/src/test/java/org/json/JSONTokenerTest.java
index de3a59a..1152e46 100644
--- a/json/src/test/java/org/json/JSONTokenerTest.java
+++ b/json/src/test/java/org/json/JSONTokenerTest.java
@@ -402,7 +402,6 @@ public class JSONTokenerTest extends TestCase {
try {
new JSONTokener("abc\\u002\"").nextString('"');
fail();
- } catch (NumberFormatException e) {
} catch (JSONException e) {
}
try {
@@ -413,13 +412,13 @@ public class JSONTokenerTest extends TestCase {
try {
new JSONTokener("abc\\u \"").nextString('"');
fail();
- } catch (NumberFormatException e) {
+ } catch (JSONException e) {
}
assertEquals("abc\"def", new JSONTokener("abc\\u0022def\"ghi").nextString('"'));
try {
new JSONTokener("abc\\u000G\"").nextString('"');
fail();
- } catch (NumberFormatException e) {
+ } catch (JSONException e) {
}
}
diff --git a/jsr166-tests/src/test/java/jsr166/AbstractExecutorServiceTest.java b/jsr166-tests/src/test/java/jsr166/AbstractExecutorServiceTest.java
index ba4cc66..9e83de2 100644
--- a/jsr166-tests/src/test/java/jsr166/AbstractExecutorServiceTest.java
+++ b/jsr166-tests/src/test/java/jsr166/AbstractExecutorServiceTest.java
@@ -8,14 +8,38 @@
package jsr166;
-import junit.framework.*;
-import java.util.*;
-import java.util.concurrent.*;
-import java.util.concurrent.atomic.AtomicBoolean;
import static java.util.concurrent.TimeUnit.MILLISECONDS;
-import java.security.*;
+
+import java.security.PrivilegedAction;
+import java.security.PrivilegedExceptionAction;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.concurrent.AbstractExecutorService;
+import java.util.concurrent.ArrayBlockingQueue;
+import java.util.concurrent.Callable;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Future;
+import java.util.concurrent.ThreadPoolExecutor;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import junit.framework.Test;
+import junit.framework.TestSuite;
public class AbstractExecutorServiceTest extends JSR166TestCase {
+ // android-note: Removed because the CTS runner does a bad job of
+ // retrying tests that have suite() declarations.
+ //
+ // public static void main(String[] args) {
+ // main(suite(), args);
+ // }
+ // public static Test suite() {
+ // return new TestSuite(...);
+ // }
/**
* A no-frills implementation of AbstractExecutorService, designed
@@ -42,11 +66,10 @@ public class AbstractExecutorServiceTest extends JSR166TestCase {
public void testExecuteRunnable() throws Exception {
ExecutorService e = new DirectExecutorService();
final AtomicBoolean done = new AtomicBoolean(false);
- CheckedRunnable task = new CheckedRunnable() {
+ Future<?> future = e.submit(new CheckedRunnable() {
public void realRun() {
done.set(true);
- }};
- Future<?> future = e.submit(task);
+ }});
assertNull(future.get());
assertNull(future.get(0, MILLISECONDS));
assertTrue(done.get());
@@ -149,8 +172,8 @@ public class AbstractExecutorServiceTest extends JSR166TestCase {
* execute(null runnable) throws NPE
*/
public void testExecuteNullRunnable() {
+ ExecutorService e = new DirectExecutorService();
try {
- ExecutorService e = new DirectExecutorService();
e.submit((Runnable) null);
shouldThrow();
} catch (NullPointerException success) {}
@@ -160,8 +183,8 @@ public class AbstractExecutorServiceTest extends JSR166TestCase {
* submit(null callable) throws NPE
*/
public void testSubmitNullCallable() {
+ ExecutorService e = new DirectExecutorService();
try {
- ExecutorService e = new DirectExecutorService();
e.submit((Callable) null);
shouldThrow();
} catch (NullPointerException success) {}
diff --git a/jsr166-tests/src/test/java/jsr166/AbstractQueueTest.java b/jsr166-tests/src/test/java/jsr166/AbstractQueueTest.java
index e74fc3c..2aa7326 100644
--- a/jsr166-tests/src/test/java/jsr166/AbstractQueueTest.java
+++ b/jsr166-tests/src/test/java/jsr166/AbstractQueueTest.java
@@ -8,13 +8,24 @@
package jsr166;
-import junit.framework.*;
import java.util.AbstractQueue;
import java.util.Arrays;
import java.util.Iterator;
import java.util.NoSuchElementException;
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
public class AbstractQueueTest extends JSR166TestCase {
+ // android-note: Removed because the CTS runner does a bad job of
+ // retrying tests that have suite() declarations.
+ //
+ // public static void main(String[] args) {
+ // main(suite(), args);
+ // }
+ // public static Test suite() {
+ // return new TestSuite(...);
+ // }
static class Succeed extends AbstractQueue<Integer> {
public boolean offer(Integer x) {
@@ -110,8 +121,8 @@ public class AbstractQueueTest extends JSR166TestCase {
* addAll(null) throws NPE
*/
public void testAddAll1() {
+ Succeed q = new Succeed();
try {
- Succeed q = new Succeed();
q.addAll(null);
shouldThrow();
} catch (NullPointerException success) {}
@@ -121,8 +132,8 @@ public class AbstractQueueTest extends JSR166TestCase {
* addAll(this) throws IAE
*/
public void testAddAllSelf() {
+ Succeed q = new Succeed();
try {
- Succeed q = new Succeed();
q.addAll(q);
shouldThrow();
} catch (IllegalArgumentException success) {}
@@ -132,9 +143,9 @@ public class AbstractQueueTest extends JSR166TestCase {
* addAll of a collection with null elements throws NPE
*/
public void testAddAll2() {
+ Succeed q = new Succeed();
+ Integer[] ints = new Integer[SIZE];
try {
- Succeed q = new Succeed();
- Integer[] ints = new Integer[SIZE];
q.addAll(Arrays.asList(ints));
shouldThrow();
} catch (NullPointerException success) {}
@@ -145,11 +156,11 @@ public class AbstractQueueTest extends JSR166TestCase {
* possibly adding some elements
*/
public void testAddAll3() {
+ Succeed q = new Succeed();
+ Integer[] ints = new Integer[SIZE];
+ for (int i = 0; i < SIZE-1; ++i)
+ ints[i] = new Integer(i);
try {
- Succeed q = new Succeed();
- Integer[] ints = new Integer[SIZE];
- for (int i = 0; i < SIZE-1; ++i)
- ints[i] = new Integer(i);
q.addAll(Arrays.asList(ints));
shouldThrow();
} catch (NullPointerException success) {}
@@ -159,11 +170,11 @@ public class AbstractQueueTest extends JSR166TestCase {
* addAll throws ISE if an add fails
*/
public void testAddAll4() {
+ Fail q = new Fail();
+ Integer[] ints = new Integer[SIZE];
+ for (int i = 0; i < SIZE; ++i)
+ ints[i] = new Integer(i);
try {
- Fail q = new Fail();
- Integer[] ints = new Integer[SIZE];
- for (int i = 0; i < SIZE; ++i)
- ints[i] = new Integer(i);
q.addAll(Arrays.asList(ints));
shouldThrow();
} catch (IllegalStateException success) {}
diff --git a/jsr166-tests/src/test/java/jsr166/AbstractQueuedLongSynchronizerTest.java b/jsr166-tests/src/test/java/jsr166/AbstractQueuedLongSynchronizerTest.java
index d957e61..8604d86 100644
--- a/jsr166-tests/src/test/java/jsr166/AbstractQueuedLongSynchronizerTest.java
+++ b/jsr166-tests/src/test/java/jsr166/AbstractQueuedLongSynchronizerTest.java
@@ -8,13 +8,29 @@
package jsr166;
-import junit.framework.*;
-import java.util.*;
import static java.util.concurrent.TimeUnit.MILLISECONDS;
+import static java.util.concurrent.TimeUnit.NANOSECONDS;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.HashSet;
import java.util.concurrent.locks.AbstractQueuedLongSynchronizer;
import java.util.concurrent.locks.AbstractQueuedLongSynchronizer.ConditionObject;
+import junit.framework.AssertionFailedError;
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
public class AbstractQueuedLongSynchronizerTest extends JSR166TestCase {
+ // android-note: Removed because the CTS runner does a bad job of
+ // retrying tests that have suite() declarations.
+ //
+ // public static void main(String[] args) {
+ // main(suite(), args);
+ // }
+ // public static Test suite() {
+ // return new TestSuite(...);
+ // }
/**
* A simple mutex class, adapted from the class javadoc. Exclusive
@@ -83,7 +99,7 @@ public class AbstractQueuedLongSynchronizerTest extends JSR166TestCase {
}
public boolean tryReleaseShared(long ignore) {
- setState(1 << 62);
+ setState(1L << 62);
return true;
}
}
@@ -191,7 +207,7 @@ public class AbstractQueuedLongSynchronizerTest extends JSR166TestCase {
new HashSet<Thread>(Arrays.asList(threads)));
}
- enum AwaitMethod { await, awaitTimed, awaitNanos, awaitUntil };
+ enum AwaitMethod { await, awaitTimed, awaitNanos, awaitUntil }
/**
* Awaits condition using the specified AwaitMethod.
@@ -214,6 +230,8 @@ public class AbstractQueuedLongSynchronizerTest extends JSR166TestCase {
case awaitUntil:
assertTrue(c.awaitUntil(delayedDate(timeoutMillis)));
break;
+ default:
+ throw new AssertionError();
}
}
@@ -1184,7 +1202,6 @@ public class AbstractQueuedLongSynchronizerTest extends JSR166TestCase {
public void testTryAcquireSharedNanos_Timeout() {
final BooleanLatch l = new BooleanLatch();
final BooleanLatch observedQueued = new BooleanLatch();
- final long timeoutMillis = timeoutMillis();
Thread t = newStartedThread(new CheckedRunnable() {
public void realRun() throws InterruptedException {
assertFalse(l.isSignalled());
@@ -1206,4 +1223,28 @@ public class AbstractQueuedLongSynchronizerTest extends JSR166TestCase {
assertFalse(l.isSignalled());
}
+ /**
+ * awaitNanos/timed await with 0 wait times out immediately
+ */
+ public void testAwait_Zero() throws InterruptedException {
+ final Mutex sync = new Mutex();
+ final ConditionObject c = sync.newCondition();
+ sync.acquire();
+ assertTrue(c.awaitNanos(0L) <= 0);
+ assertFalse(c.await(0L, NANOSECONDS));
+ sync.release();
+ }
+
+ /**
+ * awaitNanos/timed await with maximum negative wait times does not underflow
+ */
+ public void testAwait_NegativeInfinity() throws InterruptedException {
+ final Mutex sync = new Mutex();
+ final ConditionObject c = sync.newCondition();
+ sync.acquire();
+ assertTrue(c.awaitNanos(Long.MIN_VALUE) <= 0);
+ assertFalse(c.await(Long.MIN_VALUE, NANOSECONDS));
+ sync.release();
+ }
+
}
diff --git a/jsr166-tests/src/test/java/jsr166/AbstractQueuedSynchronizerTest.java b/jsr166-tests/src/test/java/jsr166/AbstractQueuedSynchronizerTest.java
index b9dab06..b3c4110 100644
--- a/jsr166-tests/src/test/java/jsr166/AbstractQueuedSynchronizerTest.java
+++ b/jsr166-tests/src/test/java/jsr166/AbstractQueuedSynchronizerTest.java
@@ -8,13 +8,29 @@
package jsr166;
-import junit.framework.*;
-import java.util.*;
import static java.util.concurrent.TimeUnit.MILLISECONDS;
+import static java.util.concurrent.TimeUnit.NANOSECONDS;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.HashSet;
import java.util.concurrent.locks.AbstractQueuedSynchronizer;
import java.util.concurrent.locks.AbstractQueuedSynchronizer.ConditionObject;
+import junit.framework.AssertionFailedError;
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
public class AbstractQueuedSynchronizerTest extends JSR166TestCase {
+ // android-note: Removed because the CTS runner does a bad job of
+ // retrying tests that have suite() declarations.
+ //
+ // public static void main(String[] args) {
+ // main(suite(), args);
+ // }
+ // public static Test suite() {
+ // return new TestSuite(...);
+ // }
/**
* A simple mutex class, adapted from the class javadoc. Exclusive
@@ -194,7 +210,7 @@ public class AbstractQueuedSynchronizerTest extends JSR166TestCase {
new HashSet<Thread>(Arrays.asList(threads)));
}
- enum AwaitMethod { await, awaitTimed, awaitNanos, awaitUntil };
+ enum AwaitMethod { await, awaitTimed, awaitNanos, awaitUntil }
/**
* Awaits condition using the specified AwaitMethod.
@@ -217,6 +233,8 @@ public class AbstractQueuedSynchronizerTest extends JSR166TestCase {
case awaitUntil:
assertTrue(c.awaitUntil(delayedDate(timeoutMillis)));
break;
+ default:
+ throw new AssertionError();
}
}
@@ -1187,7 +1205,6 @@ public class AbstractQueuedSynchronizerTest extends JSR166TestCase {
public void testTryAcquireSharedNanos_Timeout() {
final BooleanLatch l = new BooleanLatch();
final BooleanLatch observedQueued = new BooleanLatch();
- final long timeoutMillis = timeoutMillis();
Thread t = newStartedThread(new CheckedRunnable() {
public void realRun() throws InterruptedException {
assertFalse(l.isSignalled());
@@ -1209,4 +1226,28 @@ public class AbstractQueuedSynchronizerTest extends JSR166TestCase {
assertFalse(l.isSignalled());
}
+ /**
+ * awaitNanos/timed await with 0 wait times out immediately
+ */
+ public void testAwait_Zero() throws InterruptedException {
+ final Mutex sync = new Mutex();
+ final ConditionObject c = sync.newCondition();
+ sync.acquire();
+ assertTrue(c.awaitNanos(0L) <= 0);
+ assertFalse(c.await(0L, NANOSECONDS));
+ sync.release();
+ }
+
+ /**
+ * awaitNanos/timed await with maximum negative wait times does not underflow
+ */
+ public void testAwait_NegativeInfinity() throws InterruptedException {
+ final Mutex sync = new Mutex();
+ final ConditionObject c = sync.newCondition();
+ sync.acquire();
+ assertTrue(c.awaitNanos(Long.MIN_VALUE) <= 0);
+ assertFalse(c.await(Long.MIN_VALUE, NANOSECONDS));
+ sync.release();
+ }
+
}
diff --git a/jsr166-tests/src/test/java/jsr166/ArrayBlockingQueueNotFairTest.java b/jsr166-tests/src/test/java/jsr166/ArrayBlockingQueueNonFairTest.java
index ddb1c5d..7bd920f 100644
--- a/jsr166-tests/src/test/java/jsr166/ArrayBlockingQueueNotFairTest.java
+++ b/jsr166-tests/src/test/java/jsr166/ArrayBlockingQueueNonFairTest.java
@@ -11,7 +11,7 @@ package jsr166;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
-public class ArrayBlockingQueueNotFairTest extends BlockingQueueTest {
+public class ArrayBlockingQueueNonFairTest extends BlockingQueueTest {
protected BlockingQueue emptyCollection() {
return new ArrayBlockingQueue(SIZE, false);
diff --git a/jsr166-tests/src/test/java/jsr166/ArrayBlockingQueueTest.java b/jsr166-tests/src/test/java/jsr166/ArrayBlockingQueueTest.java
index b999496..247c90e 100644
--- a/jsr166-tests/src/test/java/jsr166/ArrayBlockingQueueTest.java
+++ b/jsr166-tests/src/test/java/jsr166/ArrayBlockingQueueTest.java
@@ -8,9 +8,10 @@
package jsr166;
-import junit.framework.*;
-import java.util.Arrays;
+import static java.util.concurrent.TimeUnit.MILLISECONDS;
+
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Collection;
import java.util.Iterator;
import java.util.NoSuchElementException;
@@ -20,10 +21,36 @@ import java.util.concurrent.BlockingQueue;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Executors;
import java.util.concurrent.ExecutorService;
-import static java.util.concurrent.TimeUnit.MILLISECONDS;
+
+import junit.framework.Test;
public class ArrayBlockingQueueTest extends JSR166TestCase {
+ // android-note: These tests have been moved into their own separate
+ // classes to work around CTS issues.
+ //
+ // public static class Fair extends BlockingQueueTest {
+ // protected BlockingQueue emptyCollection() {
+ // return new ArrayBlockingQueue(SIZE, true);
+ // }
+ // }
+ //
+ // public static class NonFair extends BlockingQueueTest {
+ // protected BlockingQueue emptyCollection() {
+ // return new ArrayBlockingQueue(SIZE, false);
+ // }
+ // }
+ //
+ // public static void main(String[] args) {
+ // main(suite(), args);
+ // }
+ //
+ // public static Test suite() {
+ // return newTestSuite(ArrayBlockingQueueTest.class,
+ // new Fair().testSuite(),
+ // new NonFair().testSuite());
+ // }
+
/**
* Returns a new queue of given size containing consecutive
* Integers 0 ... n.
@@ -86,7 +113,7 @@ public class ArrayBlockingQueueTest extends JSR166TestCase {
ints[i] = i;
Collection<Integer> elements = Arrays.asList(ints);
try {
- new ArrayBlockingQueue(SIZE, false, Arrays.asList(ints));
+ new ArrayBlockingQueue(SIZE, false, elements);
shouldThrow();
} catch (NullPointerException success) {}
}
@@ -137,16 +164,16 @@ public class ArrayBlockingQueueTest extends JSR166TestCase {
* remainingCapacity decreases on add, increases on remove
*/
public void testRemainingCapacity() {
- ArrayBlockingQueue q = populatedQueue(SIZE);
+ BlockingQueue q = populatedQueue(SIZE);
for (int i = 0; i < SIZE; ++i) {
assertEquals(i, q.remainingCapacity());
- assertEquals(SIZE-i, q.size());
- q.remove();
+ assertEquals(SIZE, q.size() + q.remainingCapacity());
+ assertEquals(i, q.remove());
}
for (int i = 0; i < SIZE; ++i) {
assertEquals(SIZE-i, q.remainingCapacity());
- assertEquals(i, q.size());
- q.add(new Integer(i));
+ assertEquals(SIZE, q.size() + q.remainingCapacity());
+ assertTrue(q.add(i));
}
}
@@ -163,12 +190,12 @@ public class ArrayBlockingQueueTest extends JSR166TestCase {
* add succeeds if not full; throws ISE if full
*/
public void testAdd() {
+ ArrayBlockingQueue q = new ArrayBlockingQueue(SIZE);
+ for (int i = 0; i < SIZE; ++i) {
+ assertTrue(q.add(new Integer(i)));
+ }
+ assertEquals(0, q.remainingCapacity());
try {
- ArrayBlockingQueue q = new ArrayBlockingQueue(SIZE);
- for (int i = 0; i < SIZE; ++i) {
- assertTrue(q.add(new Integer(i)));
- }
- assertEquals(0, q.remainingCapacity());
q.add(new Integer(SIZE));
shouldThrow();
} catch (IllegalStateException success) {}
@@ -178,8 +205,8 @@ public class ArrayBlockingQueueTest extends JSR166TestCase {
* addAll(this) throws IAE
*/
public void testAddAllSelf() {
+ ArrayBlockingQueue q = populatedQueue(SIZE);
try {
- ArrayBlockingQueue q = populatedQueue(SIZE);
q.addAll(q);
shouldThrow();
} catch (IllegalArgumentException success) {}
@@ -190,11 +217,11 @@ public class ArrayBlockingQueueTest extends JSR166TestCase {
* possibly adding some elements
*/
public void testAddAll3() {
+ ArrayBlockingQueue q = new ArrayBlockingQueue(SIZE);
+ Integer[] ints = new Integer[SIZE];
+ for (int i = 0; i < SIZE-1; ++i)
+ ints[i] = new Integer(i);
try {
- ArrayBlockingQueue q = new ArrayBlockingQueue(SIZE);
- Integer[] ints = new Integer[SIZE];
- for (int i = 0; i < SIZE-1; ++i)
- ints[i] = new Integer(i);
q.addAll(Arrays.asList(ints));
shouldThrow();
} catch (NullPointerException success) {}
@@ -204,11 +231,11 @@ public class ArrayBlockingQueueTest extends JSR166TestCase {
* addAll throws ISE if not enough room
*/
public void testAddAll4() {
+ ArrayBlockingQueue q = new ArrayBlockingQueue(1);
+ Integer[] ints = new Integer[SIZE];
+ for (int i = 0; i < SIZE; ++i)
+ ints[i] = new Integer(i);
try {
- ArrayBlockingQueue q = new ArrayBlockingQueue(1);
- Integer[] ints = new Integer[SIZE];
- for (int i = 0; i < SIZE; ++i)
- ints[i] = new Integer(i);
q.addAll(Arrays.asList(ints));
shouldThrow();
} catch (IllegalStateException success) {}
@@ -235,9 +262,9 @@ public class ArrayBlockingQueueTest extends JSR166TestCase {
public void testPut() throws InterruptedException {
ArrayBlockingQueue q = new ArrayBlockingQueue(SIZE);
for (int i = 0; i < SIZE; ++i) {
- Integer I = new Integer(i);
- q.put(I);
- assertTrue(q.contains(I));
+ Integer x = new Integer(i);
+ q.put(x);
+ assertTrue(q.contains(x));
}
assertEquals(0, q.remainingCapacity());
}
@@ -565,8 +592,8 @@ public class ArrayBlockingQueueTest extends JSR166TestCase {
assertTrue(q.removeAll(p));
assertEquals(SIZE-i, q.size());
for (int j = 0; j < i; ++j) {
- Integer I = (Integer)(p.remove());
- assertFalse(q.contains(I));
+ Integer x = (Integer)(p.remove());
+ assertFalse(q.contains(x));
}
}
}
@@ -676,9 +703,24 @@ public class ArrayBlockingQueueTest extends JSR166TestCase {
public void testIterator() throws InterruptedException {
ArrayBlockingQueue q = populatedQueue(SIZE);
Iterator it = q.iterator();
- while (it.hasNext()) {
+ int i;
+ for (i = 0; it.hasNext(); i++)
+ assertTrue(q.contains(it.next()));
+ assertEquals(i, SIZE);
+ assertIteratorExhausted(it);
+
+ it = q.iterator();
+ for (i = 0; it.hasNext(); i++)
assertEquals(it.next(), q.take());
- }
+ assertEquals(i, SIZE);
+ assertIteratorExhausted(it);
+ }
+
+ /**
+ * iterator of empty collection has no elements
+ */
+ public void testEmptyIterator() {
+ assertIteratorExhausted(new ArrayBlockingQueue(SIZE).iterator());
}
/**
@@ -872,8 +914,22 @@ public class ArrayBlockingQueueTest extends JSR166TestCase {
assertEquals(SIZE-k, q.size());
for (int j = 0; j < k; ++j)
assertEquals(l.get(j), new Integer(j));
- while (q.poll() != null) ;
+ do {} while (q.poll() != null);
}
}
+ /**
+ * remove(null), contains(null) always return false
+ */
+ public void testNeverContainsNull() {
+ Collection<?>[] qs = {
+ new ArrayBlockingQueue<Object>(10),
+ populatedQueue(2),
+ };
+
+ for (Collection<?> q : qs) {
+ assertFalse(q.contains(null));
+ assertFalse(q.remove(null));
+ }
+ }
}
diff --git a/jsr166-tests/src/test/java/jsr166/ArrayDequeTest.java b/jsr166-tests/src/test/java/jsr166/ArrayDequeTest.java
index d18a560..16290e9 100644
--- a/jsr166-tests/src/test/java/jsr166/ArrayDequeTest.java
+++ b/jsr166-tests/src/test/java/jsr166/ArrayDequeTest.java
@@ -6,9 +6,8 @@
package jsr166;
-import junit.framework.*;
-import java.util.Arrays;
import java.util.ArrayDeque;
+import java.util.Arrays;
import java.util.Collection;
import java.util.Deque;
import java.util.Iterator;
@@ -16,7 +15,19 @@ import java.util.NoSuchElementException;
import java.util.Queue;
import java.util.Random;
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
public class ArrayDequeTest extends JSR166TestCase {
+ // android-note: Removed because the CTS runner does a bad job of
+ // retrying tests that have suite() declarations.
+ //
+ // public static void main(String[] args) {
+ // main(suite(), args);
+ // }
+ // public static Test suite() {
+ // return new TestSuite(...);
+ // }
/**
* Returns a new deque of given size containing consecutive
@@ -44,7 +55,7 @@ public class ArrayDequeTest extends JSR166TestCase {
*/
public void testConstructor3() {
try {
- ArrayDeque q = new ArrayDeque((Collection)null);
+ new ArrayDeque((Collection)null);
shouldThrow();
} catch (NullPointerException success) {}
}
@@ -55,7 +66,7 @@ public class ArrayDequeTest extends JSR166TestCase {
public void testConstructor4() {
try {
Integer[] ints = new Integer[SIZE];
- ArrayDeque q = new ArrayDeque(Arrays.asList(ints));
+ new ArrayDeque(Arrays.asList(ints));
shouldThrow();
} catch (NullPointerException success) {}
}
@@ -68,7 +79,7 @@ public class ArrayDequeTest extends JSR166TestCase {
Integer[] ints = new Integer[SIZE];
for (int i = 0; i < SIZE-1; ++i)
ints[i] = new Integer(i);
- ArrayDeque q = new ArrayDeque(Arrays.asList(ints));
+ new ArrayDeque(Arrays.asList(ints));
shouldThrow();
} catch (NullPointerException success) {}
}
@@ -386,13 +397,13 @@ public class ArrayDequeTest extends JSR166TestCase {
*/
public void testRemoveElement() {
ArrayDeque q = populatedDeque(SIZE);
- for (int i = 1; i < SIZE; i+=2) {
+ for (int i = 1; i < SIZE; i += 2) {
assertTrue(q.contains(i));
assertTrue(q.remove(i));
assertFalse(q.contains(i));
assertTrue(q.contains(i-1));
}
- for (int i = 0; i < SIZE; i+=2) {
+ for (int i = 0; i < SIZE; i += 2) {
assertTrue(q.contains(i));
assertTrue(q.remove(i));
assertFalse(q.contains(i));
@@ -525,10 +536,10 @@ public class ArrayDequeTest extends JSR166TestCase {
*/
public void testRemoveFirstOccurrence() {
ArrayDeque q = populatedDeque(SIZE);
- for (int i = 1; i < SIZE; i+=2) {
+ for (int i = 1; i < SIZE; i += 2) {
assertTrue(q.removeFirstOccurrence(new Integer(i)));
}
- for (int i = 0; i < SIZE; i+=2) {
+ for (int i = 0; i < SIZE; i += 2) {
assertTrue(q.removeFirstOccurrence(new Integer(i)));
assertFalse(q.removeFirstOccurrence(new Integer(i+1)));
}
@@ -540,10 +551,10 @@ public class ArrayDequeTest extends JSR166TestCase {
*/
public void testRemoveLastOccurrence() {
ArrayDeque q = populatedDeque(SIZE);
- for (int i = 1; i < SIZE; i+=2) {
+ for (int i = 1; i < SIZE; i += 2) {
assertTrue(q.removeLastOccurrence(new Integer(i)));
}
- for (int i = 0; i < SIZE; i+=2) {
+ for (int i = 0; i < SIZE; i += 2) {
assertTrue(q.removeLastOccurrence(new Integer(i)));
assertFalse(q.removeLastOccurrence(new Integer(i+1)));
}
@@ -735,13 +746,21 @@ public class ArrayDequeTest extends JSR166TestCase {
*/
public void testIterator() {
ArrayDeque q = populatedDeque(SIZE);
- int i = 0;
Iterator it = q.iterator();
- while (it.hasNext()) {
+ int i;
+ for (i = 0; it.hasNext(); i++)
assertTrue(q.contains(it.next()));
- ++i;
- }
assertEquals(i, SIZE);
+ assertIteratorExhausted(it);
+ }
+
+ /**
+ * iterator of empty collection has no elements
+ */
+ public void testEmptyIterator() {
+ Deque c = new ArrayDeque();
+ assertIteratorExhausted(c.iterator());
+ assertIteratorExhausted(c.descendingIterator());
}
/**
@@ -885,4 +904,21 @@ public class ArrayDequeTest extends JSR166TestCase {
assertTrue(y.isEmpty());
}
+ /**
+ * remove(null), contains(null) always return false
+ */
+ public void testNeverContainsNull() {
+ Deque<?>[] qs = {
+ new ArrayDeque<Object>(),
+ populatedDeque(2),
+ };
+
+ for (Deque<?> q : qs) {
+ assertFalse(q.contains(null));
+ assertFalse(q.remove(null));
+ assertFalse(q.removeFirstOccurrence(null));
+ assertFalse(q.removeLastOccurrence(null));
+ }
+ }
+
}
diff --git a/jsr166-tests/src/test/java/jsr166/AtomicBooleanTest.java b/jsr166-tests/src/test/java/jsr166/AtomicBooleanTest.java
index 7a50120..bfe3fc6 100644
--- a/jsr166-tests/src/test/java/jsr166/AtomicBooleanTest.java
+++ b/jsr166-tests/src/test/java/jsr166/AtomicBooleanTest.java
@@ -8,10 +8,21 @@
package jsr166;
-import junit.framework.*;
import java.util.concurrent.atomic.AtomicBoolean;
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
public class AtomicBooleanTest extends JSR166TestCase {
+ // android-note: Removed because the CTS runner does a bad job of
+ // retrying tests that have suite() declarations.
+ //
+ // public static void main(String[] args) {
+ // main(suite(), args);
+ // }
+ // public static Test suite() {
+ // return new TestSuite(...);
+ // }
/**
* constructor initializes to given value
@@ -91,11 +102,11 @@ public class AtomicBooleanTest extends JSR166TestCase {
*/
public void testWeakCompareAndSet() {
AtomicBoolean ai = new AtomicBoolean(true);
- while (!ai.weakCompareAndSet(true, false));
+ do {} while (!ai.weakCompareAndSet(true, false));
assertFalse(ai.get());
- while (!ai.weakCompareAndSet(false, false));
+ do {} while (!ai.weakCompareAndSet(false, false));
assertFalse(ai.get());
- while (!ai.weakCompareAndSet(false, true));
+ do {} while (!ai.weakCompareAndSet(false, true));
assertTrue(ai.get());
}
diff --git a/jsr166-tests/src/test/java/jsr166/AtomicIntegerArrayTest.java b/jsr166-tests/src/test/java/jsr166/AtomicIntegerArrayTest.java
index e81a107..670b9ce 100644
--- a/jsr166-tests/src/test/java/jsr166/AtomicIntegerArrayTest.java
+++ b/jsr166-tests/src/test/java/jsr166/AtomicIntegerArrayTest.java
@@ -8,11 +8,22 @@
package jsr166;
-import junit.framework.*;
import java.util.Arrays;
import java.util.concurrent.atomic.AtomicIntegerArray;
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
public class AtomicIntegerArrayTest extends JSR166TestCase {
+ // android-note: Removed because the CTS runner does a bad job of
+ // retrying tests that have suite() declarations.
+ //
+ // public static void main(String[] args) {
+ // main(suite(), args);
+ // }
+ // public static Test suite() {
+ // return new TestSuite(...);
+ // }
/**
* constructor creates array of given size with all elements zero
@@ -29,7 +40,7 @@ public class AtomicIntegerArrayTest extends JSR166TestCase {
public void testConstructor2NPE() {
try {
int[] a = null;
- AtomicIntegerArray aa = new AtomicIntegerArray(a);
+ new AtomicIntegerArray(a);
shouldThrow();
} catch (NullPointerException success) {}
}
@@ -157,10 +168,10 @@ public class AtomicIntegerArrayTest extends JSR166TestCase {
AtomicIntegerArray aa = new AtomicIntegerArray(SIZE);
for (int i = 0; i < SIZE; i++) {
aa.set(i, 1);
- while (!aa.weakCompareAndSet(i, 1, 2));
- while (!aa.weakCompareAndSet(i, 2, -4));
+ do {} while (!aa.weakCompareAndSet(i, 1, 2));
+ do {} while (!aa.weakCompareAndSet(i, 2, -4));
assertEquals(-4, aa.get(i));
- while (!aa.weakCompareAndSet(i, -4, 7));
+ do {} while (!aa.weakCompareAndSet(i, -4, 7));
assertEquals(7, aa.get(i));
}
}
@@ -267,8 +278,6 @@ public class AtomicIntegerArrayTest extends JSR166TestCase {
}
}
- static final int COUNTDOWN = 100000;
-
class Counter extends CheckedRunnable {
final AtomicIntegerArray aa;
volatile int counts;
@@ -297,8 +306,9 @@ public class AtomicIntegerArrayTest extends JSR166TestCase {
*/
public void testCountingInMultipleThreads() throws InterruptedException {
final AtomicIntegerArray aa = new AtomicIntegerArray(SIZE);
+ int countdown = 10000;
for (int i = 0; i < SIZE; i++)
- aa.set(i, COUNTDOWN);
+ aa.set(i, countdown);
Counter c1 = new Counter(aa);
Counter c2 = new Counter(aa);
Thread t1 = new Thread(c1);
@@ -307,7 +317,7 @@ public class AtomicIntegerArrayTest extends JSR166TestCase {
t2.start();
t1.join();
t2.join();
- assertEquals(c1.counts+c2.counts, SIZE * COUNTDOWN);
+ assertEquals(c1.counts+c2.counts, SIZE * countdown);
}
/**
diff --git a/jsr166-tests/src/test/java/jsr166/AtomicIntegerFieldUpdaterTest.java b/jsr166-tests/src/test/java/jsr166/AtomicIntegerFieldUpdaterTest.java
index f0c1ae6..ef75b46 100644
--- a/jsr166-tests/src/test/java/jsr166/AtomicIntegerFieldUpdaterTest.java
+++ b/jsr166-tests/src/test/java/jsr166/AtomicIntegerFieldUpdaterTest.java
@@ -8,13 +8,24 @@
package jsr166;
-import junit.framework.*;
import java.util.concurrent.atomic.AtomicIntegerFieldUpdater;
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
public class AtomicIntegerFieldUpdaterTest extends JSR166TestCase {
volatile int x = 0;
int w;
long z;
+ // android-note: Removed because the CTS runner does a bad job of
+ // retrying tests that have suite() declarations.
+ //
+ // public static void main(String[] args) {
+ // main(suite(), args);
+ // }
+ // public static Test suite() {
+ // return new TestSuite(...);
+ // }
AtomicIntegerFieldUpdater<AtomicIntegerFieldUpdaterTest> updaterFor(String fieldName) {
return AtomicIntegerFieldUpdater.newUpdater
@@ -127,10 +138,10 @@ public class AtomicIntegerFieldUpdaterTest extends JSR166TestCase {
AtomicIntegerFieldUpdater<AtomicIntegerFieldUpdaterTest> a;
a = updaterFor("x");
x = 1;
- while (!a.weakCompareAndSet(this, 1, 2));
- while (!a.weakCompareAndSet(this, 2, -4));
+ do {} while (!a.weakCompareAndSet(this, 1, 2));
+ do {} while (!a.weakCompareAndSet(this, 2, -4));
assertEquals(-4, a.get(this));
- while (!a.weakCompareAndSet(this, -4, 7));
+ do {} while (!a.weakCompareAndSet(this, -4, 7));
assertEquals(7, a.get(this));
}
diff --git a/jsr166-tests/src/test/java/jsr166/AtomicIntegerTest.java b/jsr166-tests/src/test/java/jsr166/AtomicIntegerTest.java
index 2afaa73..cf73810 100644
--- a/jsr166-tests/src/test/java/jsr166/AtomicIntegerTest.java
+++ b/jsr166-tests/src/test/java/jsr166/AtomicIntegerTest.java
@@ -8,10 +8,21 @@
package jsr166;
-import junit.framework.*;
import java.util.concurrent.atomic.AtomicInteger;
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
public class AtomicIntegerTest extends JSR166TestCase {
+ // android-note: Removed because the CTS runner does a bad job of
+ // retrying tests that have suite() declarations.
+ //
+ // public static void main(String[] args) {
+ // main(suite(), args);
+ // }
+ // public static Test suite() {
+ // return new TestSuite(...);
+ // }
final int[] VALUES = {
Integer.MIN_VALUE, -1, 0, 1, 42, Integer.MAX_VALUE,
@@ -96,10 +107,10 @@ public class AtomicIntegerTest extends JSR166TestCase {
*/
public void testWeakCompareAndSet() {
AtomicInteger ai = new AtomicInteger(1);
- while (!ai.weakCompareAndSet(1, 2));
- while (!ai.weakCompareAndSet(2, -4));
+ do {} while (!ai.weakCompareAndSet(1, 2));
+ do {} while (!ai.weakCompareAndSet(2, -4));
assertEquals(-4, ai.get());
- while (!ai.weakCompareAndSet(-4, 7));
+ do {} while (!ai.weakCompareAndSet(-4, 7));
assertEquals(7, ai.get());
}
diff --git a/jsr166-tests/src/test/java/jsr166/AtomicLongArrayTest.java b/jsr166-tests/src/test/java/jsr166/AtomicLongArrayTest.java
index 53be5dc..08df01e 100644
--- a/jsr166-tests/src/test/java/jsr166/AtomicLongArrayTest.java
+++ b/jsr166-tests/src/test/java/jsr166/AtomicLongArrayTest.java
@@ -8,11 +8,22 @@
package jsr166;
-import junit.framework.*;
import java.util.Arrays;
import java.util.concurrent.atomic.AtomicLongArray;
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
public class AtomicLongArrayTest extends JSR166TestCase {
+ // android-note: Removed because the CTS runner does a bad job of
+ // retrying tests that have suite() declarations.
+ //
+ // public static void main(String[] args) {
+ // main(suite(), args);
+ // }
+ // public static Test suite() {
+ // return new TestSuite(...);
+ // }
/**
* constructor creates array of given size with all elements zero
@@ -29,7 +40,7 @@ public class AtomicLongArrayTest extends JSR166TestCase {
public void testConstructor2NPE() {
try {
long[] a = null;
- AtomicLongArray aa = new AtomicLongArray(a);
+ new AtomicLongArray(a);
shouldThrow();
} catch (NullPointerException success) {}
}
@@ -157,10 +168,10 @@ public class AtomicLongArrayTest extends JSR166TestCase {
AtomicLongArray aa = new AtomicLongArray(SIZE);
for (int i = 0; i < SIZE; i++) {
aa.set(i, 1);
- while (!aa.weakCompareAndSet(i, 1, 2));
- while (!aa.weakCompareAndSet(i, 2, -4));
+ do {} while (!aa.weakCompareAndSet(i, 1, 2));
+ do {} while (!aa.weakCompareAndSet(i, 2, -4));
assertEquals(-4, aa.get(i));
- while (!aa.weakCompareAndSet(i, -4, 7));
+ do {} while (!aa.weakCompareAndSet(i, -4, 7));
assertEquals(7, aa.get(i));
}
}
@@ -267,8 +278,6 @@ public class AtomicLongArrayTest extends JSR166TestCase {
}
}
- static final long COUNTDOWN = 100000;
-
class Counter extends CheckedRunnable {
final AtomicLongArray aa;
volatile long counts;
@@ -297,8 +306,9 @@ public class AtomicLongArrayTest extends JSR166TestCase {
*/
public void testCountingInMultipleThreads() throws InterruptedException {
final AtomicLongArray aa = new AtomicLongArray(SIZE);
+ long countdown = 10000;
for (int i = 0; i < SIZE; i++)
- aa.set(i, COUNTDOWN);
+ aa.set(i, countdown);
Counter c1 = new Counter(aa);
Counter c2 = new Counter(aa);
Thread t1 = new Thread(c1);
@@ -307,7 +317,7 @@ public class AtomicLongArrayTest extends JSR166TestCase {
t2.start();
t1.join();
t2.join();
- assertEquals(c1.counts+c2.counts, SIZE * COUNTDOWN);
+ assertEquals(c1.counts+c2.counts, SIZE * countdown);
}
/**
diff --git a/jsr166-tests/src/test/java/jsr166/AtomicLongFieldUpdaterTest.java b/jsr166-tests/src/test/java/jsr166/AtomicLongFieldUpdaterTest.java
index c9374e0..204f814 100644
--- a/jsr166-tests/src/test/java/jsr166/AtomicLongFieldUpdaterTest.java
+++ b/jsr166-tests/src/test/java/jsr166/AtomicLongFieldUpdaterTest.java
@@ -8,14 +8,26 @@
package jsr166;
-import junit.framework.*;
import java.util.concurrent.atomic.AtomicLongFieldUpdater;
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
public class AtomicLongFieldUpdaterTest extends JSR166TestCase {
volatile long x = 0;
int z;
long w;
+ // android-note: Removed because the CTS runner does a bad job of
+ // retrying tests that have suite() declarations.
+ //
+ // public static void main(String[] args) {
+ // main(suite(), args);
+ // }
+ // public static Test suite() {
+ // return new TestSuite(...);
+ // }
+
AtomicLongFieldUpdater<AtomicLongFieldUpdaterTest> updaterFor(String fieldName) {
return AtomicLongFieldUpdater.newUpdater
(AtomicLongFieldUpdaterTest.class, fieldName);
@@ -127,10 +139,10 @@ public class AtomicLongFieldUpdaterTest extends JSR166TestCase {
AtomicLongFieldUpdater<AtomicLongFieldUpdaterTest> a;
a = updaterFor("x");
x = 1;
- while (!a.weakCompareAndSet(this, 1, 2));
- while (!a.weakCompareAndSet(this, 2, -4));
+ do {} while (!a.weakCompareAndSet(this, 1, 2));
+ do {} while (!a.weakCompareAndSet(this, 2, -4));
assertEquals(-4, a.get(this));
- while (!a.weakCompareAndSet(this, -4, 7));
+ do {} while (!a.weakCompareAndSet(this, -4, 7));
assertEquals(7, a.get(this));
}
diff --git a/jsr166-tests/src/test/java/jsr166/AtomicLongTest.java b/jsr166-tests/src/test/java/jsr166/AtomicLongTest.java
index d300367..b9c1722 100644
--- a/jsr166-tests/src/test/java/jsr166/AtomicLongTest.java
+++ b/jsr166-tests/src/test/java/jsr166/AtomicLongTest.java
@@ -8,10 +8,21 @@
package jsr166;
-import junit.framework.*;
import java.util.concurrent.atomic.AtomicLong;
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
public class AtomicLongTest extends JSR166TestCase {
+ // android-note: Removed because the CTS runner does a bad job of
+ // retrying tests that have suite() declarations.
+ //
+ // public static void main(String[] args) {
+ // main(suite(), args);
+ // }
+ // public static Test suite() {
+ // return new TestSuite(...);
+ // }
final long[] VALUES = {
Long.MIN_VALUE,
@@ -98,10 +109,10 @@ public class AtomicLongTest extends JSR166TestCase {
*/
public void testWeakCompareAndSet() {
AtomicLong ai = new AtomicLong(1);
- while (!ai.weakCompareAndSet(1, 2));
- while (!ai.weakCompareAndSet(2, -4));
+ do {} while (!ai.weakCompareAndSet(1, 2));
+ do {} while (!ai.weakCompareAndSet(2, -4));
assertEquals(-4, ai.get());
- while (!ai.weakCompareAndSet(-4, 7));
+ do {} while (!ai.weakCompareAndSet(-4, 7));
assertEquals(7, ai.get());
}
diff --git a/jsr166-tests/src/test/java/jsr166/AtomicMarkableReferenceTest.java b/jsr166-tests/src/test/java/jsr166/AtomicMarkableReferenceTest.java
index fd1f2f1..61b6b1b 100644
--- a/jsr166-tests/src/test/java/jsr166/AtomicMarkableReferenceTest.java
+++ b/jsr166-tests/src/test/java/jsr166/AtomicMarkableReferenceTest.java
@@ -8,10 +8,21 @@
package jsr166;
-import junit.framework.*;
import java.util.concurrent.atomic.AtomicMarkableReference;
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
public class AtomicMarkableReferenceTest extends JSR166TestCase {
+ // android-note: Removed because the CTS runner does a bad job of
+ // retrying tests that have suite() declarations.
+ //
+ // public static void main(String[] args) {
+ // main(suite(), args);
+ // }
+ // public static Test suite() {
+ // return new TestSuite(...);
+ // }
/**
* constructor initializes to given reference and mark
@@ -135,11 +146,11 @@ public class AtomicMarkableReferenceTest extends JSR166TestCase {
assertFalse(ai.isMarked());
assertFalse(mark[0]);
- while (!ai.weakCompareAndSet(one, two, false, false));
+ do {} while (!ai.weakCompareAndSet(one, two, false, false));
assertSame(two, ai.get(mark));
assertFalse(mark[0]);
- while (!ai.weakCompareAndSet(two, m3, false, true));
+ do {} while (!ai.weakCompareAndSet(two, m3, false, true));
assertSame(m3, ai.get(mark));
assertTrue(mark[0]);
}
diff --git a/jsr166-tests/src/test/java/jsr166/AtomicReferenceArrayTest.java b/jsr166-tests/src/test/java/jsr166/AtomicReferenceArrayTest.java
index 0a4f3d9..1df2f9f 100644
--- a/jsr166-tests/src/test/java/jsr166/AtomicReferenceArrayTest.java
+++ b/jsr166-tests/src/test/java/jsr166/AtomicReferenceArrayTest.java
@@ -8,11 +8,22 @@
package jsr166;
-import junit.framework.*;
import java.util.Arrays;
import java.util.concurrent.atomic.AtomicReferenceArray;
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
public class AtomicReferenceArrayTest extends JSR166TestCase {
+ // android-note: Removed because the CTS runner does a bad job of
+ // retrying tests that have suite() declarations.
+ //
+ // public static void main(String[] args) {
+ // main(suite(), args);
+ // }
+ // public static Test suite() {
+ // return new TestSuite(...);
+ // }
/**
* constructor creates array of given size with all elements null
@@ -30,7 +41,7 @@ public class AtomicReferenceArrayTest extends JSR166TestCase {
public void testConstructor2NPE() {
try {
Integer[] a = null;
- AtomicReferenceArray<Integer> aa = new AtomicReferenceArray<Integer>(a);
+ new AtomicReferenceArray<Integer>(a);
shouldThrow();
} catch (NullPointerException success) {}
}
@@ -165,10 +176,10 @@ public class AtomicReferenceArrayTest extends JSR166TestCase {
AtomicReferenceArray aa = new AtomicReferenceArray(SIZE);
for (int i = 0; i < SIZE; i++) {
aa.set(i, one);
- while (!aa.weakCompareAndSet(i, one, two));
- while (!aa.weakCompareAndSet(i, two, m4));
+ do {} while (!aa.weakCompareAndSet(i, one, two));
+ do {} while (!aa.weakCompareAndSet(i, two, m4));
assertSame(m4, aa.get(i));
- while (!aa.weakCompareAndSet(i, m4, seven));
+ do {} while (!aa.weakCompareAndSet(i, m4, seven));
assertSame(seven, aa.get(i));
}
}
diff --git a/jsr166-tests/src/test/java/jsr166/AtomicReferenceFieldUpdaterTest.java b/jsr166-tests/src/test/java/jsr166/AtomicReferenceFieldUpdaterTest.java
index 271c7b7..4b0d946 100644
--- a/jsr166-tests/src/test/java/jsr166/AtomicReferenceFieldUpdaterTest.java
+++ b/jsr166-tests/src/test/java/jsr166/AtomicReferenceFieldUpdaterTest.java
@@ -8,15 +8,27 @@
package jsr166;
-import junit.framework.*;
import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
public class AtomicReferenceFieldUpdaterTest extends JSR166TestCase {
volatile Integer x = null;
Object z;
Integer w;
volatile int i;
+ // android-note: Removed because the CTS runner does a bad job of
+ // retrying tests that have suite() declarations.
+ //
+ // public static void main(String[] args) {
+ // main(suite(), args);
+ // }
+ // public static Test suite() {
+ // return new TestSuite(...);
+ // }
+
AtomicReferenceFieldUpdater<AtomicReferenceFieldUpdaterTest, Integer> updaterFor(String fieldName) {
return AtomicReferenceFieldUpdater.newUpdater
(AtomicReferenceFieldUpdaterTest.class, Integer.class, fieldName);
@@ -68,7 +80,7 @@ public class AtomicReferenceFieldUpdaterTest extends JSR166TestCase {
* get returns the last value set or assigned
*/
public void testGetSet() {
- AtomicReferenceFieldUpdater<AtomicReferenceFieldUpdaterTest, Integer>a;
+ AtomicReferenceFieldUpdater<AtomicReferenceFieldUpdaterTest, Integer> a;
a = updaterFor("x");
x = one;
assertSame(one, a.get(this));
@@ -82,7 +94,7 @@ public class AtomicReferenceFieldUpdaterTest extends JSR166TestCase {
* get returns the last value lazySet by same thread
*/
public void testGetLazySet() {
- AtomicReferenceFieldUpdater<AtomicReferenceFieldUpdaterTest, Integer>a;
+ AtomicReferenceFieldUpdater<AtomicReferenceFieldUpdaterTest, Integer> a;
a = updaterFor("x");
x = one;
assertSame(one, a.get(this));
@@ -96,7 +108,7 @@ public class AtomicReferenceFieldUpdaterTest extends JSR166TestCase {
* compareAndSet succeeds in changing value if equal to expected else fails
*/
public void testCompareAndSet() {
- AtomicReferenceFieldUpdater<AtomicReferenceFieldUpdaterTest, Integer>a;
+ AtomicReferenceFieldUpdater<AtomicReferenceFieldUpdaterTest, Integer> a;
a = updaterFor("x");
x = one;
assertTrue(a.compareAndSet(this, one, two));
@@ -114,7 +126,7 @@ public class AtomicReferenceFieldUpdaterTest extends JSR166TestCase {
*/
public void testCompareAndSetInMultipleThreads() throws Exception {
x = one;
- final AtomicReferenceFieldUpdater<AtomicReferenceFieldUpdaterTest, Integer>a;
+ final AtomicReferenceFieldUpdater<AtomicReferenceFieldUpdaterTest, Integer> a;
a = updaterFor("x");
Thread t = new Thread(new CheckedRunnable() {
@@ -135,13 +147,13 @@ public class AtomicReferenceFieldUpdaterTest extends JSR166TestCase {
* to expected
*/
public void testWeakCompareAndSet() {
- AtomicReferenceFieldUpdater<AtomicReferenceFieldUpdaterTest, Integer>a;
+ AtomicReferenceFieldUpdater<AtomicReferenceFieldUpdaterTest, Integer> a;
a = updaterFor("x");
x = one;
- while (!a.weakCompareAndSet(this, one, two));
- while (!a.weakCompareAndSet(this, two, m4));
+ do {} while (!a.weakCompareAndSet(this, one, two));
+ do {} while (!a.weakCompareAndSet(this, two, m4));
assertSame(m4, a.get(this));
- while (!a.weakCompareAndSet(this, m4, seven));
+ do {} while (!a.weakCompareAndSet(this, m4, seven));
assertSame(seven, a.get(this));
}
@@ -149,7 +161,7 @@ public class AtomicReferenceFieldUpdaterTest extends JSR166TestCase {
* getAndSet returns previous value and sets to given value
*/
public void testGetAndSet() {
- AtomicReferenceFieldUpdater<AtomicReferenceFieldUpdaterTest, Integer>a;
+ AtomicReferenceFieldUpdater<AtomicReferenceFieldUpdaterTest, Integer> a;
a = updaterFor("x");
x = one;
assertSame(one, a.getAndSet(this, zero));
diff --git a/jsr166-tests/src/test/java/jsr166/AtomicReferenceTest.java b/jsr166-tests/src/test/java/jsr166/AtomicReferenceTest.java
index 8032546..457182f 100644
--- a/jsr166-tests/src/test/java/jsr166/AtomicReferenceTest.java
+++ b/jsr166-tests/src/test/java/jsr166/AtomicReferenceTest.java
@@ -8,10 +8,21 @@
package jsr166;
-import junit.framework.*;
import java.util.concurrent.atomic.AtomicReference;
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
public class AtomicReferenceTest extends JSR166TestCase {
+ // android-note: Removed because the CTS runner does a bad job of
+ // retrying tests that have suite() declarations.
+ //
+ // public static void main(String[] args) {
+ // main(suite(), args);
+ // }
+ // public static Test suite() {
+ // return new TestSuite(...);
+ // }
/**
* constructor initializes to given value
@@ -92,10 +103,10 @@ public class AtomicReferenceTest extends JSR166TestCase {
*/
public void testWeakCompareAndSet() {
AtomicReference ai = new AtomicReference(one);
- while (!ai.weakCompareAndSet(one, two));
- while (!ai.weakCompareAndSet(two, m4));
+ do {} while (!ai.weakCompareAndSet(one, two));
+ do {} while (!ai.weakCompareAndSet(two, m4));
assertSame(m4, ai.get());
- while (!ai.weakCompareAndSet(m4, seven));
+ do {} while (!ai.weakCompareAndSet(m4, seven));
assertSame(seven, ai.get());
}
diff --git a/jsr166-tests/src/test/java/jsr166/AtomicStampedReferenceTest.java b/jsr166-tests/src/test/java/jsr166/AtomicStampedReferenceTest.java
index 3e6445e..b3ff06a 100644
--- a/jsr166-tests/src/test/java/jsr166/AtomicStampedReferenceTest.java
+++ b/jsr166-tests/src/test/java/jsr166/AtomicStampedReferenceTest.java
@@ -8,10 +8,21 @@
package jsr166;
-import junit.framework.*;
import java.util.concurrent.atomic.AtomicStampedReference;
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
public class AtomicStampedReferenceTest extends JSR166TestCase {
+ // android-note: Removed because the CTS runner does a bad job of
+ // retrying tests that have suite() declarations.
+ //
+ // public static void main(String[] args) {
+ // main(suite(), args);
+ // }
+ // public static Test suite() {
+ // return new TestSuite(...);
+ // }
/**
* constructor initializes to given reference and stamp
@@ -135,11 +146,11 @@ public class AtomicStampedReferenceTest extends JSR166TestCase {
assertEquals(0, ai.getStamp());
assertEquals(0, mark[0]);
- while (!ai.weakCompareAndSet(one, two, 0, 0));
+ do {} while (!ai.weakCompareAndSet(one, two, 0, 0));
assertSame(two, ai.get(mark));
assertEquals(0, mark[0]);
- while (!ai.weakCompareAndSet(two, m3, 0, 1));
+ do {} while (!ai.weakCompareAndSet(two, m3, 0, 1));
assertSame(m3, ai.get(mark));
assertEquals(1, mark[0]);
}
diff --git a/jsr166-tests/src/test/java/jsr166/BlockingQueueTest.java b/jsr166-tests/src/test/java/jsr166/BlockingQueueTest.java
index 1ed7559..db0f03d 100644
--- a/jsr166-tests/src/test/java/jsr166/BlockingQueueTest.java
+++ b/jsr166-tests/src/test/java/jsr166/BlockingQueueTest.java
@@ -9,14 +9,17 @@
package jsr166;
-import junit.framework.*;
+import static java.util.concurrent.TimeUnit.MILLISECONDS;
+
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Queue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.CountDownLatch;
-import static java.util.concurrent.TimeUnit.MILLISECONDS;
+
+import junit.framework.Test;
+import junit.framework.TestSuite;
/**
* Contains "contract" tests applicable to all BlockingQueue implementations.
@@ -32,6 +35,15 @@ public abstract class BlockingQueueTest extends JSR166TestCase {
* instances.
*/
+ /** Like suite(), but non-static */
+ // android-note: Explicitly instantiated.
+ //
+ // public Test testSuite() {
+ // // TODO: filter the returned tests using the configuration
+ // // information provided by the subclass via protected methods.
+ // return new TestSuite(this.getClass());
+ // }
+
//----------------------------------------------------------------
// Configuration methods
//----------------------------------------------------------------
@@ -335,7 +347,7 @@ public abstract class BlockingQueueTest extends JSR166TestCase {
checkEmpty(q);
for (int i = 0; i < size; i++)
q.add(elts[i] = makeElement(i));
- for (int i = 1; i < size; i+=2) {
+ for (int i = 1; i < size; i += 2) {
for (int pass = 0; pass < 2; pass++) {
assertEquals((pass == 0), q.contains(elts[i]));
assertEquals((pass == 0), q.remove(elts[i]));
@@ -347,7 +359,7 @@ public abstract class BlockingQueueTest extends JSR166TestCase {
}
if (size > 0)
assertTrue(q.contains(elts[0]));
- for (int i = size-2; i >= 0; i-=2) {
+ for (int i = size-2; i >= 0; i -= 2) {
assertTrue(q.contains(elts[i]));
assertFalse(q.contains(elts[i+1]));
assertTrue(q.remove(elts[i]));
diff --git a/jsr166-tests/src/test/java/jsr166/ConcurrentHashMapTest.java b/jsr166-tests/src/test/java/jsr166/ConcurrentHashMapTest.java
index 5d9e2ac..4650f41 100644
--- a/jsr166-tests/src/test/java/jsr166/ConcurrentHashMapTest.java
+++ b/jsr166-tests/src/test/java/jsr166/ConcurrentHashMapTest.java
@@ -8,17 +8,36 @@
package jsr166;
-import junit.framework.*;
-import java.util.*;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Random;
+import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
public class ConcurrentHashMapTest extends JSR166TestCase {
+ // android-note: Removed because the CTS runner does a bad job of
+ // retrying tests that have suite() declarations.
+ //
+ // public static void main(String[] args) {
+ // main(suite(), args);
+ // }
+ // public static Test suite() {
+ // return new TestSuite(...);
+ // }
/**
* Returns a new map from Integers 1-5 to Strings "A"-"E".
*/
- private static ConcurrentHashMap map5() {
- ConcurrentHashMap map = new ConcurrentHashMap(5);
+ private static ConcurrentHashMap<Integer, String> map5() {
+ ConcurrentHashMap map = new ConcurrentHashMap<Integer, String>(5);
assertTrue(map.isEmpty());
map.put(one, "A");
map.put(two, "B");
@@ -30,12 +49,15 @@ public class ConcurrentHashMapTest extends JSR166TestCase {
return map;
}
+ /** Re-implement Integer.compare for old java versions */
+ static int compare(int x, int y) { return x < y ? -1 : x > y ? 1 : 0; }
+
// classes for testing Comparable fallbacks
static class BI implements Comparable<BI> {
private final int value;
BI(int value) { this.value = value; }
public int compareTo(BI other) {
- return Integer.compare(value, other.value);
+ return compare(value, other.value);
}
public boolean equals(Object x) {
return (x instanceof BI) && ((BI)x).value == value;
@@ -59,12 +81,9 @@ public class ConcurrentHashMapTest extends JSR166TestCase {
static class LexicographicList<E extends Comparable<E>> extends ArrayList<E>
implements Comparable<LexicographicList<E>> {
- static long total;
- static long n;
LexicographicList(Collection<E> c) { super(c); }
LexicographicList(E e) { super(Collections.singleton(e)); }
public int compareTo(LexicographicList<E> other) {
- long start = System.currentTimeMillis();
int common = Math.min(size(), other.size());
int r = 0;
for (int i = 0; i < common; i++) {
@@ -72,25 +91,40 @@ public class ConcurrentHashMapTest extends JSR166TestCase {
break;
}
if (r == 0)
- r = Integer.compare(size(), other.size());
- total += System.currentTimeMillis() - start;
- n++;
+ r = compare(size(), other.size());
return r;
}
private static final long serialVersionUID = 0;
}
+ static class CollidingObject {
+ final String value;
+ CollidingObject(final String value) { this.value = value; }
+ public int hashCode() { return this.value.hashCode() & 1; }
+ public boolean equals(final Object obj) {
+ return (obj instanceof CollidingObject) && ((CollidingObject)obj).value.equals(value);
+ }
+ }
+
+ static class ComparableCollidingObject extends CollidingObject implements Comparable<ComparableCollidingObject> {
+ ComparableCollidingObject(final String value) { super(value); }
+ public int compareTo(final ComparableCollidingObject o) {
+ return value.compareTo(o.value);
+ }
+ }
+
/**
* Inserted elements that are subclasses of the same Comparable
* class are found.
*/
public void testComparableFamily() {
+ int size = 500; // makes measured test run time -> 60ms
ConcurrentHashMap<BI, Boolean> m =
new ConcurrentHashMap<BI, Boolean>();
- for (int i = 0; i < 1000; i++) {
+ for (int i = 0; i < size; i++) {
assertTrue(m.put(new CI(i), true) == null);
}
- for (int i = 0; i < 1000; i++) {
+ for (int i = 0; i < size; i++) {
assertTrue(m.containsKey(new CI(i)));
assertTrue(m.containsKey(new DI(i)));
}
@@ -100,24 +134,25 @@ public class ConcurrentHashMapTest extends JSR166TestCase {
* Elements of classes with erased generic type parameters based
* on Comparable can be inserted and found.
*/
- public void testGenericComparable() {
- ConcurrentHashMap<Object, Boolean> m =
- new ConcurrentHashMap<Object, Boolean>();
- for (int i = 0; i < 1000; i++) {
- BI bi = new BI(i);
- BS bs = new BS(String.valueOf(i));
- LexicographicList<BI> bis = new LexicographicList<BI>(bi);
- LexicographicList<BS> bss = new LexicographicList<BS>(bs);
- assertTrue(m.putIfAbsent(bis, true) == null);
- assertTrue(m.containsKey(bis));
- if (m.putIfAbsent(bss, true) == null)
- assertTrue(m.containsKey(bss));
- assertTrue(m.containsKey(bis));
- }
- for (int i = 0; i < 1000; i++) {
- assertTrue(m.containsKey(new ArrayList(Collections.singleton(new BI(i)))));
- }
- }
+ public void testGenericComparable() {
+ int size = 120; // makes measured test run time -> 60ms
+ ConcurrentHashMap<Object, Boolean> m =
+ new ConcurrentHashMap<Object, Boolean>();
+ for (int i = 0; i < size; i++) {
+ BI bi = new BI(i);
+ BS bs = new BS(String.valueOf(i));
+ LexicographicList<BI> bis = new LexicographicList<BI>(bi);
+ LexicographicList<BS> bss = new LexicographicList<BS>(bs);
+ assertTrue(m.putIfAbsent(bis, true) == null);
+ assertTrue(m.containsKey(bis));
+ if (m.putIfAbsent(bss, true) == null)
+ assertTrue(m.containsKey(bss));
+ assertTrue(m.containsKey(bis));
+ }
+ for (int i = 0; i < size; i++) {
+ assertTrue(m.containsKey(Collections.singletonList(new BI(i))));
+ }
+ }
/**
* Elements of non-comparable classes equal to those of classes
@@ -125,19 +160,55 @@ public class ConcurrentHashMapTest extends JSR166TestCase {
* inserted and found.
*/
public void testGenericComparable2() {
+ int size = 500; // makes measured test run time -> 60ms
ConcurrentHashMap<Object, Boolean> m =
new ConcurrentHashMap<Object, Boolean>();
- for (int i = 0; i < 1000; i++) {
- m.put(new ArrayList(Collections.singleton(new BI(i))), true);
+ for (int i = 0; i < size; i++) {
+ m.put(Collections.singletonList(new BI(i)), true);
}
- for (int i = 0; i < 1000; i++) {
+ for (int i = 0; i < size; i++) {
LexicographicList<BI> bis = new LexicographicList<BI>(new BI(i));
assertTrue(m.containsKey(bis));
}
}
/**
+ * Mixtures of instances of comparable and non-comparable classes
+ * can be inserted and found.
+ */
+ public void testMixedComparable() {
+ int size = 1200; // makes measured test run time -> 35ms
+ ConcurrentHashMap<Object, Object> map =
+ new ConcurrentHashMap<Object, Object>();
+ Random rng = new Random();
+ for (int i = 0; i < size; i++) {
+ Object x;
+ switch (rng.nextInt(4)) {
+ case 0:
+ x = new Object();
+ break;
+ case 1:
+ x = new CollidingObject(Integer.toString(i));
+ break;
+ default:
+ x = new ComparableCollidingObject(Integer.toString(i));
+ }
+ assertNull(map.put(x, x));
+ }
+ int count = 0;
+ for (Object k : map.keySet()) {
+ assertEquals(map.get(k), k);
+ ++count;
+ }
+ assertEquals(count, size);
+ assertEquals(map.size(), size);
+ for (Object k : map.keySet()) {
+ assertEquals(map.put(k, k), k);
+ }
+ }
+
+ /**
* clear removes all pairs
*/
public void testClear() {
@@ -160,6 +231,17 @@ public class ConcurrentHashMapTest extends JSR166TestCase {
}
/**
+ * hashCode() equals sum of each key.hashCode ^ value.hashCode
+ */
+ public void testHashCode() {
+ ConcurrentHashMap<Integer,String> map = map5();
+ int sum = 0;
+ for (Map.Entry<Integer,String> e : map.entrySet())
+ sum += e.getKey().hashCode() ^ e.getValue().hashCode();
+ assertEquals(sum, map.hashCode());
+ }
+
+ /**
* contains returns true for contained value
*/
public void testContains() {
@@ -210,6 +292,7 @@ public class ConcurrentHashMapTest extends JSR166TestCase {
assertEquals("A", (String)map.get(one));
ConcurrentHashMap empty = new ConcurrentHashMap();
assertNull(map.get("anything"));
+ assertNull(empty.get("anything"));
}
/**
@@ -443,41 +526,81 @@ public class ConcurrentHashMapTest extends JSR166TestCase {
// Exception tests
/**
- * Cannot create with negative capacity
+ * Cannot create with only negative capacity
*/
public void testConstructor1() {
try {
- new ConcurrentHashMap(-1,0,1);
+ new ConcurrentHashMap(-1);
shouldThrow();
} catch (IllegalArgumentException success) {}
}
/**
- * Cannot create with negative concurrency level
- */
+ * Constructor (initialCapacity, loadFactor) throws
+ * IllegalArgumentException if either argument is negative
+ */
public void testConstructor2() {
try {
- new ConcurrentHashMap(1,0,-1);
+ new ConcurrentHashMap(-1, .75f);
+ shouldThrow();
+ } catch (IllegalArgumentException success) {}
+
+ try {
+ new ConcurrentHashMap(16, -1);
shouldThrow();
} catch (IllegalArgumentException success) {}
}
/**
- * Cannot create with only negative capacity
+ * Constructor (initialCapacity, loadFactor, concurrencyLevel)
+ * throws IllegalArgumentException if any argument is negative
*/
public void testConstructor3() {
try {
- new ConcurrentHashMap(-1);
+ new ConcurrentHashMap(-1, .75f, 1);
+ shouldThrow();
+ } catch (IllegalArgumentException success) {}
+
+ try {
+ new ConcurrentHashMap(16, -1, 1);
+ shouldThrow();
+ } catch (IllegalArgumentException success) {}
+
+ try {
+ new ConcurrentHashMap(16, .75f, -1);
shouldThrow();
} catch (IllegalArgumentException success) {}
}
/**
+ * ConcurrentHashMap(map) throws NullPointerException if the given
+ * map is null
+ */
+ public void testConstructor4() {
+ try {
+ new ConcurrentHashMap(null);
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ }
+
+ /**
+ * ConcurrentHashMap(map) creates a new map with the same mappings
+ * as the given map
+ */
+ public void testConstructor5() {
+ ConcurrentHashMap map1 = map5();
+ ConcurrentHashMap map2 = new ConcurrentHashMap(map5());
+ assertTrue(map2.equals(map1));
+ map2.put(one, "F");
+ assertFalse(map2.equals(map1));
+ }
+
+ /**
* get(null) throws NPE
*/
public void testGet_NullPointerException() {
+ ConcurrentHashMap c = new ConcurrentHashMap(5);
try {
- ConcurrentHashMap c = new ConcurrentHashMap(5);
c.get(null);
shouldThrow();
} catch (NullPointerException success) {}
@@ -487,8 +610,8 @@ public class ConcurrentHashMapTest extends JSR166TestCase {
* containsKey(null) throws NPE
*/
public void testContainsKey_NullPointerException() {
+ ConcurrentHashMap c = new ConcurrentHashMap(5);
try {
- ConcurrentHashMap c = new ConcurrentHashMap(5);
c.containsKey(null);
shouldThrow();
} catch (NullPointerException success) {}
@@ -498,8 +621,8 @@ public class ConcurrentHashMapTest extends JSR166TestCase {
* containsValue(null) throws NPE
*/
public void testContainsValue_NullPointerException() {
+ ConcurrentHashMap c = new ConcurrentHashMap(5);
try {
- ConcurrentHashMap c = new ConcurrentHashMap(5);
c.containsValue(null);
shouldThrow();
} catch (NullPointerException success) {}
@@ -509,8 +632,8 @@ public class ConcurrentHashMapTest extends JSR166TestCase {
* contains(null) throws NPE
*/
public void testContains_NullPointerException() {
+ ConcurrentHashMap c = new ConcurrentHashMap(5);
try {
- ConcurrentHashMap c = new ConcurrentHashMap(5);
c.contains(null);
shouldThrow();
} catch (NullPointerException success) {}
@@ -520,8 +643,8 @@ public class ConcurrentHashMapTest extends JSR166TestCase {
* put(null,x) throws NPE
*/
public void testPut1_NullPointerException() {
+ ConcurrentHashMap c = new ConcurrentHashMap(5);
try {
- ConcurrentHashMap c = new ConcurrentHashMap(5);
c.put(null, "whatever");
shouldThrow();
} catch (NullPointerException success) {}
@@ -531,8 +654,8 @@ public class ConcurrentHashMapTest extends JSR166TestCase {
* put(x, null) throws NPE
*/
public void testPut2_NullPointerException() {
+ ConcurrentHashMap c = new ConcurrentHashMap(5);
try {
- ConcurrentHashMap c = new ConcurrentHashMap(5);
c.put("whatever", null);
shouldThrow();
} catch (NullPointerException success) {}
@@ -542,8 +665,8 @@ public class ConcurrentHashMapTest extends JSR166TestCase {
* putIfAbsent(null, x) throws NPE
*/
public void testPutIfAbsent1_NullPointerException() {
+ ConcurrentHashMap c = new ConcurrentHashMap(5);
try {
- ConcurrentHashMap c = new ConcurrentHashMap(5);
c.putIfAbsent(null, "whatever");
shouldThrow();
} catch (NullPointerException success) {}
@@ -553,8 +676,8 @@ public class ConcurrentHashMapTest extends JSR166TestCase {
* replace(null, x) throws NPE
*/
public void testReplace_NullPointerException() {
+ ConcurrentHashMap c = new ConcurrentHashMap(5);
try {
- ConcurrentHashMap c = new ConcurrentHashMap(5);
c.replace(null, "whatever");
shouldThrow();
} catch (NullPointerException success) {}
@@ -564,8 +687,8 @@ public class ConcurrentHashMapTest extends JSR166TestCase {
* replace(null, x, y) throws NPE
*/
public void testReplaceValue_NullPointerException() {
+ ConcurrentHashMap c = new ConcurrentHashMap(5);
try {
- ConcurrentHashMap c = new ConcurrentHashMap(5);
c.replace(null, one, "whatever");
shouldThrow();
} catch (NullPointerException success) {}
@@ -575,8 +698,8 @@ public class ConcurrentHashMapTest extends JSR166TestCase {
* putIfAbsent(x, null) throws NPE
*/
public void testPutIfAbsent2_NullPointerException() {
+ ConcurrentHashMap c = new ConcurrentHashMap(5);
try {
- ConcurrentHashMap c = new ConcurrentHashMap(5);
c.putIfAbsent("whatever", null);
shouldThrow();
} catch (NullPointerException success) {}
@@ -586,8 +709,8 @@ public class ConcurrentHashMapTest extends JSR166TestCase {
* replace(x, null) throws NPE
*/
public void testReplace2_NullPointerException() {
+ ConcurrentHashMap c = new ConcurrentHashMap(5);
try {
- ConcurrentHashMap c = new ConcurrentHashMap(5);
c.replace("whatever", null);
shouldThrow();
} catch (NullPointerException success) {}
@@ -597,8 +720,8 @@ public class ConcurrentHashMapTest extends JSR166TestCase {
* replace(x, null, y) throws NPE
*/
public void testReplaceValue2_NullPointerException() {
+ ConcurrentHashMap c = new ConcurrentHashMap(5);
try {
- ConcurrentHashMap c = new ConcurrentHashMap(5);
c.replace("whatever", null, "A");
shouldThrow();
} catch (NullPointerException success) {}
@@ -608,8 +731,8 @@ public class ConcurrentHashMapTest extends JSR166TestCase {
* replace(x, y, null) throws NPE
*/
public void testReplaceValue3_NullPointerException() {
+ ConcurrentHashMap c = new ConcurrentHashMap(5);
try {
- ConcurrentHashMap c = new ConcurrentHashMap(5);
c.replace("whatever", one, null);
shouldThrow();
} catch (NullPointerException success) {}
@@ -619,9 +742,9 @@ public class ConcurrentHashMapTest extends JSR166TestCase {
* remove(null) throws NPE
*/
public void testRemove1_NullPointerException() {
+ ConcurrentHashMap c = new ConcurrentHashMap(5);
+ c.put("sadsdf", "asdads");
try {
- ConcurrentHashMap c = new ConcurrentHashMap(5);
- c.put("sadsdf", "asdads");
c.remove(null);
shouldThrow();
} catch (NullPointerException success) {}
@@ -631,9 +754,9 @@ public class ConcurrentHashMapTest extends JSR166TestCase {
* remove(null, x) throws NPE
*/
public void testRemove2_NullPointerException() {
+ ConcurrentHashMap c = new ConcurrentHashMap(5);
+ c.put("sadsdf", "asdads");
try {
- ConcurrentHashMap c = new ConcurrentHashMap(5);
- c.put("sadsdf", "asdads");
c.remove(null, "whatever");
shouldThrow();
} catch (NullPointerException success) {}
diff --git a/jsr166-tests/src/test/java/jsr166/ConcurrentLinkedDequeTest.java b/jsr166-tests/src/test/java/jsr166/ConcurrentLinkedDequeTest.java
index f5b8318..c445957 100644
--- a/jsr166-tests/src/test/java/jsr166/ConcurrentLinkedDequeTest.java
+++ b/jsr166-tests/src/test/java/jsr166/ConcurrentLinkedDequeTest.java
@@ -8,17 +8,30 @@
package jsr166;
-import junit.framework.*;
import java.util.Arrays;
import java.util.Collection;
+import java.util.Deque;
import java.util.Iterator;
import java.util.NoSuchElementException;
import java.util.Queue;
import java.util.Random;
import java.util.concurrent.ConcurrentLinkedDeque;
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
public class ConcurrentLinkedDequeTest extends JSR166TestCase {
+ // android-note: Removed because the CTS runner does a bad job of
+ // retrying tests that have suite() declarations.
+ //
+ // public static void main(String[] args) {
+ // main(suite(), args);
+ // }
+ // public static Test suite() {
+ // return new TestSuite(...);
+ // }
+
/**
* Returns a new deque of given size containing consecutive
* Integers 0 ... n.
@@ -46,7 +59,7 @@ public class ConcurrentLinkedDequeTest extends JSR166TestCase {
*/
public void testConstructor3() {
try {
- ConcurrentLinkedDeque q = new ConcurrentLinkedDeque((Collection)null);
+ new ConcurrentLinkedDeque((Collection)null);
shouldThrow();
} catch (NullPointerException success) {}
}
@@ -57,7 +70,7 @@ public class ConcurrentLinkedDequeTest extends JSR166TestCase {
public void testConstructor4() {
try {
Integer[] ints = new Integer[SIZE];
- ConcurrentLinkedDeque q = new ConcurrentLinkedDeque(Arrays.asList(ints));
+ new ConcurrentLinkedDeque(Arrays.asList(ints));
shouldThrow();
} catch (NullPointerException success) {}
}
@@ -70,7 +83,7 @@ public class ConcurrentLinkedDequeTest extends JSR166TestCase {
Integer[] ints = new Integer[SIZE];
for (int i = 0; i < SIZE-1; ++i)
ints[i] = new Integer(i);
- ConcurrentLinkedDeque q = new ConcurrentLinkedDeque(Arrays.asList(ints));
+ new ConcurrentLinkedDeque(Arrays.asList(ints));
shouldThrow();
} catch (NullPointerException success) {}
}
@@ -428,13 +441,13 @@ public class ConcurrentLinkedDequeTest extends JSR166TestCase {
*/
public void testRemoveElement() {
ConcurrentLinkedDeque q = populatedDeque(SIZE);
- for (int i = 1; i < SIZE; i+=2) {
+ for (int i = 1; i < SIZE; i += 2) {
assertTrue(q.contains(i));
assertTrue(q.remove(i));
assertFalse(q.contains(i));
assertTrue(q.contains(i-1));
}
- for (int i = 0; i < SIZE; i+=2) {
+ for (int i = 0; i < SIZE; i += 2) {
assertTrue(q.contains(i));
assertTrue(q.remove(i));
assertFalse(q.contains(i));
@@ -538,10 +551,10 @@ public class ConcurrentLinkedDequeTest extends JSR166TestCase {
*/
public void testRemoveFirstOccurrence() {
ConcurrentLinkedDeque q = populatedDeque(SIZE);
- for (int i = 1; i < SIZE; i+=2) {
+ for (int i = 1; i < SIZE; i += 2) {
assertTrue(q.removeFirstOccurrence(new Integer(i)));
}
- for (int i = 0; i < SIZE; i+=2) {
+ for (int i = 0; i < SIZE; i += 2) {
assertTrue(q.removeFirstOccurrence(new Integer(i)));
assertFalse(q.removeFirstOccurrence(new Integer(i+1)));
}
@@ -553,10 +566,10 @@ public class ConcurrentLinkedDequeTest extends JSR166TestCase {
*/
public void testRemoveLastOccurrence() {
ConcurrentLinkedDeque q = populatedDeque(SIZE);
- for (int i = 1; i < SIZE; i+=2) {
+ for (int i = 1; i < SIZE; i += 2) {
assertTrue(q.removeLastOccurrence(new Integer(i)));
}
- for (int i = 0; i < SIZE; i+=2) {
+ for (int i = 0; i < SIZE; i += 2) {
assertTrue(q.removeLastOccurrence(new Integer(i)));
assertFalse(q.removeLastOccurrence(new Integer(i+1)));
}
@@ -632,8 +645,8 @@ public class ConcurrentLinkedDequeTest extends JSR166TestCase {
assertTrue(q.removeAll(p));
assertEquals(SIZE-i, q.size());
for (int j = 0; j < i; ++j) {
- Integer I = (Integer)(p.remove());
- assertFalse(q.contains(I));
+ Integer x = (Integer)(p.remove());
+ assertFalse(q.contains(x));
}
}
}
@@ -687,13 +700,21 @@ public class ConcurrentLinkedDequeTest extends JSR166TestCase {
*/
public void testIterator() {
ConcurrentLinkedDeque q = populatedDeque(SIZE);
- int i = 0;
Iterator it = q.iterator();
- while (it.hasNext()) {
+ int i;
+ for (i = 0; it.hasNext(); i++)
assertTrue(q.contains(it.next()));
- ++i;
- }
assertEquals(i, SIZE);
+ assertIteratorExhausted(it);
+ }
+
+ /**
+ * iterator of empty collection has no elements
+ */
+ public void testEmptyIterator() {
+ Deque c = new ConcurrentLinkedDeque();
+ assertIteratorExhausted(c.iterator());
+ assertIteratorExhausted(c.descendingIterator());
}
/**
@@ -855,4 +876,30 @@ public class ConcurrentLinkedDequeTest extends JSR166TestCase {
assertTrue(y.isEmpty());
}
+ /**
+ * contains(null) always return false.
+ * remove(null) always throws NullPointerException.
+ */
+ public void testNeverContainsNull() {
+ Deque<?>[] qs = {
+ new ConcurrentLinkedDeque<Object>(),
+ populatedDeque(2),
+ };
+
+ for (Deque<?> q : qs) {
+ assertFalse(q.contains(null));
+ try {
+ assertFalse(q.remove(null));
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ try {
+ assertFalse(q.removeFirstOccurrence(null));
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ try {
+ assertFalse(q.removeLastOccurrence(null));
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ }
+ }
}
diff --git a/jsr166-tests/src/test/java/jsr166/ConcurrentLinkedQueueTest.java b/jsr166-tests/src/test/java/jsr166/ConcurrentLinkedQueueTest.java
index 7924034..d3f5b1f 100644
--- a/jsr166-tests/src/test/java/jsr166/ConcurrentLinkedQueueTest.java
+++ b/jsr166-tests/src/test/java/jsr166/ConcurrentLinkedQueueTest.java
@@ -8,7 +8,6 @@
package jsr166;
-import junit.framework.*;
import java.util.Arrays;
import java.util.Collection;
import java.util.Iterator;
@@ -16,8 +15,21 @@ import java.util.NoSuchElementException;
import java.util.Queue;
import java.util.concurrent.ConcurrentLinkedQueue;
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
public class ConcurrentLinkedQueueTest extends JSR166TestCase {
+ // android-note: Removed because the CTS runner does a bad job of
+ // retrying tests that have suite() declarations.
+ //
+ // public static void main(String[] args) {
+ // main(suite(), args);
+ // }
+ // public static Test suite() {
+ // return new TestSuite(...);
+ // }
+
/**
* Returns a new queue of given size containing consecutive
* Integers 0 ... n.
@@ -44,7 +56,7 @@ public class ConcurrentLinkedQueueTest extends JSR166TestCase {
*/
public void testConstructor3() {
try {
- ConcurrentLinkedQueue q = new ConcurrentLinkedQueue((Collection)null);
+ new ConcurrentLinkedQueue((Collection)null);
shouldThrow();
} catch (NullPointerException success) {}
}
@@ -55,7 +67,7 @@ public class ConcurrentLinkedQueueTest extends JSR166TestCase {
public void testConstructor4() {
try {
Integer[] ints = new Integer[SIZE];
- ConcurrentLinkedQueue q = new ConcurrentLinkedQueue(Arrays.asList(ints));
+ new ConcurrentLinkedQueue(Arrays.asList(ints));
shouldThrow();
} catch (NullPointerException success) {}
}
@@ -68,7 +80,7 @@ public class ConcurrentLinkedQueueTest extends JSR166TestCase {
Integer[] ints = new Integer[SIZE];
for (int i = 0; i < SIZE-1; ++i)
ints[i] = new Integer(i);
- ConcurrentLinkedQueue q = new ConcurrentLinkedQueue(Arrays.asList(ints));
+ new ConcurrentLinkedQueue(Arrays.asList(ints));
shouldThrow();
} catch (NullPointerException success) {}
}
@@ -279,13 +291,13 @@ public class ConcurrentLinkedQueueTest extends JSR166TestCase {
*/
public void testRemoveElement() {
ConcurrentLinkedQueue q = populatedQueue(SIZE);
- for (int i = 1; i < SIZE; i+=2) {
+ for (int i = 1; i < SIZE; i += 2) {
assertTrue(q.contains(i));
assertTrue(q.remove(i));
assertFalse(q.contains(i));
assertTrue(q.contains(i-1));
}
- for (int i = 0; i < SIZE; i+=2) {
+ for (int i = 0; i < SIZE; i += 2) {
assertTrue(q.contains(i));
assertTrue(q.remove(i));
assertFalse(q.contains(i));
@@ -364,8 +376,8 @@ public class ConcurrentLinkedQueueTest extends JSR166TestCase {
assertTrue(q.removeAll(p));
assertEquals(SIZE-i, q.size());
for (int j = 0; j < i; ++j) {
- Integer I = (Integer)(p.remove());
- assertFalse(q.contains(I));
+ Integer x = (Integer)(p.remove());
+ assertFalse(q.contains(x));
}
}
}
@@ -419,13 +431,19 @@ public class ConcurrentLinkedQueueTest extends JSR166TestCase {
*/
public void testIterator() {
ConcurrentLinkedQueue q = populatedQueue(SIZE);
- int i = 0;
Iterator it = q.iterator();
- while (it.hasNext()) {
+ int i;
+ for (i = 0; it.hasNext(); i++)
assertTrue(q.contains(it.next()));
- ++i;
- }
assertEquals(i, SIZE);
+ assertIteratorExhausted(it);
+ }
+
+ /**
+ * iterator of empty collection has no elements
+ */
+ public void testEmptyIterator() {
+ assertIteratorExhausted(new ConcurrentLinkedQueue().iterator());
}
/**
@@ -508,4 +526,18 @@ public class ConcurrentLinkedQueueTest extends JSR166TestCase {
assertTrue(y.isEmpty());
}
+ /**
+ * remove(null), contains(null) always return false
+ */
+ public void testNeverContainsNull() {
+ Collection<?>[] qs = {
+ new ConcurrentLinkedQueue<Object>(),
+ populatedQueue(2),
+ };
+
+ for (Collection<?> q : qs) {
+ assertFalse(q.contains(null));
+ assertFalse(q.remove(null));
+ }
+ }
}
diff --git a/jsr166-tests/src/test/java/jsr166/ConcurrentSkipListMapTest.java b/jsr166-tests/src/test/java/jsr166/ConcurrentSkipListMapTest.java
index 4359287..0aadd23 100644
--- a/jsr166-tests/src/test/java/jsr166/ConcurrentSkipListMapTest.java
+++ b/jsr166-tests/src/test/java/jsr166/ConcurrentSkipListMapTest.java
@@ -6,11 +6,32 @@
package jsr166;
-import junit.framework.*;
-import java.util.*;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.BitSet;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.NavigableMap;
+import java.util.NavigableSet;
+import java.util.NoSuchElementException;
+import java.util.Random;
+import java.util.Set;
import java.util.concurrent.ConcurrentSkipListMap;
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
public class ConcurrentSkipListMapTest extends JSR166TestCase {
+ // android-note: Removed because the CTS runner does a bad job of
+ // retrying tests that have suite() declarations.
+ //
+ // public static void main(String[] args) {
+ // main(suite(), args);
+ // }
+ // public static Test suite() {
+ // return new TestSuite(...);
+ // }
/**
* Returns a new map from Integers 1-5 to Strings "A"-"E".
@@ -678,8 +699,8 @@ public class ConcurrentSkipListMapTest extends JSR166TestCase {
* get(null) of nonempty map throws NPE
*/
public void testGet_NullPointerException() {
+ ConcurrentSkipListMap c = map5();
try {
- ConcurrentSkipListMap c = map5();
c.get(null);
shouldThrow();
} catch (NullPointerException success) {}
@@ -689,8 +710,8 @@ public class ConcurrentSkipListMapTest extends JSR166TestCase {
* containsKey(null) of nonempty map throws NPE
*/
public void testContainsKey_NullPointerException() {
+ ConcurrentSkipListMap c = map5();
try {
- ConcurrentSkipListMap c = map5();
c.containsKey(null);
shouldThrow();
} catch (NullPointerException success) {}
@@ -700,8 +721,8 @@ public class ConcurrentSkipListMapTest extends JSR166TestCase {
* containsValue(null) throws NPE
*/
public void testContainsValue_NullPointerException() {
+ ConcurrentSkipListMap c = new ConcurrentSkipListMap();
try {
- ConcurrentSkipListMap c = new ConcurrentSkipListMap();
c.containsValue(null);
shouldThrow();
} catch (NullPointerException success) {}
@@ -711,8 +732,8 @@ public class ConcurrentSkipListMapTest extends JSR166TestCase {
* put(null,x) throws NPE
*/
public void testPut1_NullPointerException() {
+ ConcurrentSkipListMap c = map5();
try {
- ConcurrentSkipListMap c = map5();
c.put(null, "whatever");
shouldThrow();
} catch (NullPointerException success) {}
@@ -722,8 +743,8 @@ public class ConcurrentSkipListMapTest extends JSR166TestCase {
* putIfAbsent(null, x) throws NPE
*/
public void testPutIfAbsent1_NullPointerException() {
+ ConcurrentSkipListMap c = map5();
try {
- ConcurrentSkipListMap c = map5();
c.putIfAbsent(null, "whatever");
shouldThrow();
} catch (NullPointerException success) {}
@@ -733,8 +754,8 @@ public class ConcurrentSkipListMapTest extends JSR166TestCase {
* replace(null, x) throws NPE
*/
public void testReplace_NullPointerException() {
+ ConcurrentSkipListMap c = map5();
try {
- ConcurrentSkipListMap c = map5();
c.replace(null, "whatever");
shouldThrow();
} catch (NullPointerException success) {}
@@ -744,8 +765,8 @@ public class ConcurrentSkipListMapTest extends JSR166TestCase {
* replace(null, x, y) throws NPE
*/
public void testReplaceValue_NullPointerException() {
+ ConcurrentSkipListMap c = map5();
try {
- ConcurrentSkipListMap c = map5();
c.replace(null, one, "whatever");
shouldThrow();
} catch (NullPointerException success) {}
@@ -755,9 +776,9 @@ public class ConcurrentSkipListMapTest extends JSR166TestCase {
* remove(null) throws NPE
*/
public void testRemove1_NullPointerException() {
+ ConcurrentSkipListMap c = new ConcurrentSkipListMap();
+ c.put("sadsdf", "asdads");
try {
- ConcurrentSkipListMap c = new ConcurrentSkipListMap();
- c.put("sadsdf", "asdads");
c.remove(null);
shouldThrow();
} catch (NullPointerException success) {}
@@ -767,9 +788,9 @@ public class ConcurrentSkipListMapTest extends JSR166TestCase {
* remove(null, x) throws NPE
*/
public void testRemove2_NullPointerException() {
+ ConcurrentSkipListMap c = new ConcurrentSkipListMap();
+ c.put("sadsdf", "asdads");
try {
- ConcurrentSkipListMap c = new ConcurrentSkipListMap();
- c.put("sadsdf", "asdads");
c.remove(null, "whatever");
shouldThrow();
} catch (NullPointerException success) {}
@@ -1014,7 +1035,7 @@ public class ConcurrentSkipListMapTest extends JSR166TestCase {
// Add entries till we're back to original size
while (map.size() < size) {
int key = min + rnd.nextInt(rangeSize);
- assertTrue(key >= min && key<= max);
+ assertTrue(key >= min && key <= max);
put(map, key);
}
}
@@ -1039,7 +1060,7 @@ public class ConcurrentSkipListMapTest extends JSR166TestCase {
// Add entries till we're back to original size
while (map.size() < size) {
int key = min - 5 + rnd.nextInt(rangeSize + 10);
- if (key >= min && key<= max) {
+ if (key >= min && key <= max) {
put(map, key);
} else {
try {
diff --git a/jsr166-tests/src/test/java/jsr166/ConcurrentSkipListSetTest.java b/jsr166-tests/src/test/java/jsr166/ConcurrentSkipListSetTest.java
index 1fd3c5f..41f8835 100644
--- a/jsr166-tests/src/test/java/jsr166/ConcurrentSkipListSetTest.java
+++ b/jsr166-tests/src/test/java/jsr166/ConcurrentSkipListSetTest.java
@@ -6,7 +6,6 @@
package jsr166;
-import junit.framework.*;
import java.util.Arrays;
import java.util.BitSet;
import java.util.Collection;
@@ -19,7 +18,19 @@ import java.util.Set;
import java.util.SortedSet;
import java.util.concurrent.ConcurrentSkipListSet;
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
public class ConcurrentSkipListSetTest extends JSR166TestCase {
+ // android-note: Removed because the CTS runner does a bad job of
+ // retrying tests that have suite() declarations.
+ //
+ // public static void main(String[] args) {
+ // main(suite(), args);
+ // }
+ // public static Test suite() {
+ // return new TestSuite(...);
+ // }
static class MyReverseComparator implements Comparator {
public int compare(Object x, Object y) {
@@ -35,9 +46,9 @@ public class ConcurrentSkipListSetTest extends JSR166TestCase {
ConcurrentSkipListSet<Integer> q =
new ConcurrentSkipListSet<Integer>();
assertTrue(q.isEmpty());
- for (int i = n-1; i >= 0; i-=2)
+ for (int i = n-1; i >= 0; i -= 2)
assertTrue(q.add(new Integer(i)));
- for (int i = (n & 1); i < n; i+=2)
+ for (int i = (n & 1); i < n; i += 2)
assertTrue(q.add(new Integer(i)));
assertFalse(q.isEmpty());
assertEquals(n, q.size());
@@ -71,7 +82,7 @@ public class ConcurrentSkipListSetTest extends JSR166TestCase {
*/
public void testConstructor3() {
try {
- ConcurrentSkipListSet q = new ConcurrentSkipListSet((Collection)null);
+ new ConcurrentSkipListSet((Collection)null);
shouldThrow();
} catch (NullPointerException success) {}
}
@@ -82,7 +93,7 @@ public class ConcurrentSkipListSetTest extends JSR166TestCase {
public void testConstructor4() {
try {
Integer[] ints = new Integer[SIZE];
- ConcurrentSkipListSet q = new ConcurrentSkipListSet(Arrays.asList(ints));
+ new ConcurrentSkipListSet(Arrays.asList(ints));
shouldThrow();
} catch (NullPointerException success) {}
}
@@ -95,7 +106,7 @@ public class ConcurrentSkipListSetTest extends JSR166TestCase {
Integer[] ints = new Integer[SIZE];
for (int i = 0; i < SIZE-1; ++i)
ints[i] = new Integer(i);
- ConcurrentSkipListSet q = new ConcurrentSkipListSet(Arrays.asList(ints));
+ new ConcurrentSkipListSet(Arrays.asList(ints));
shouldThrow();
} catch (NullPointerException success) {}
}
@@ -160,8 +171,8 @@ public class ConcurrentSkipListSetTest extends JSR166TestCase {
* add(null) throws NPE
*/
public void testAddNull() {
+ ConcurrentSkipListSet q = new ConcurrentSkipListSet();
try {
- ConcurrentSkipListSet q = new ConcurrentSkipListSet();
q.add(null);
shouldThrow();
} catch (NullPointerException success) {}
@@ -189,9 +200,8 @@ public class ConcurrentSkipListSetTest extends JSR166TestCase {
* Add of non-Comparable throws CCE
*/
public void testAddNonComparable() {
+ ConcurrentSkipListSet q = new ConcurrentSkipListSet();
try {
- ConcurrentSkipListSet q = new ConcurrentSkipListSet();
- q.add(new Object());
q.add(new Object());
q.add(new Object());
shouldThrow();
@@ -202,8 +212,8 @@ public class ConcurrentSkipListSetTest extends JSR166TestCase {
* addAll(null) throws NPE
*/
public void testAddAll1() {
+ ConcurrentSkipListSet q = new ConcurrentSkipListSet();
try {
- ConcurrentSkipListSet q = new ConcurrentSkipListSet();
q.addAll(null);
shouldThrow();
} catch (NullPointerException success) {}
@@ -213,9 +223,9 @@ public class ConcurrentSkipListSetTest extends JSR166TestCase {
* addAll of a collection with null elements throws NPE
*/
public void testAddAll2() {
+ ConcurrentSkipListSet q = new ConcurrentSkipListSet();
+ Integer[] ints = new Integer[SIZE];
try {
- ConcurrentSkipListSet q = new ConcurrentSkipListSet();
- Integer[] ints = new Integer[SIZE];
q.addAll(Arrays.asList(ints));
shouldThrow();
} catch (NullPointerException success) {}
@@ -226,11 +236,11 @@ public class ConcurrentSkipListSetTest extends JSR166TestCase {
* possibly adding some elements
*/
public void testAddAll3() {
+ ConcurrentSkipListSet q = new ConcurrentSkipListSet();
+ Integer[] ints = new Integer[SIZE];
+ for (int i = 0; i < SIZE-1; ++i)
+ ints[i] = new Integer(i);
try {
- ConcurrentSkipListSet q = new ConcurrentSkipListSet();
- Integer[] ints = new Integer[SIZE];
- for (int i = 0; i < SIZE-1; ++i)
- ints[i] = new Integer(i);
q.addAll(Arrays.asList(ints));
shouldThrow();
} catch (NullPointerException success) {}
@@ -278,13 +288,13 @@ public class ConcurrentSkipListSetTest extends JSR166TestCase {
*/
public void testRemoveElement() {
ConcurrentSkipListSet q = populatedSet(SIZE);
- for (int i = 1; i < SIZE; i+=2) {
+ for (int i = 1; i < SIZE; i += 2) {
assertTrue(q.contains(i));
assertTrue(q.remove(i));
assertFalse(q.contains(i));
assertTrue(q.contains(i-1));
}
- for (int i = 0; i < SIZE; i+=2) {
+ for (int i = 0; i < SIZE; i += 2) {
assertTrue(q.contains(i));
assertTrue(q.remove(i));
assertFalse(q.contains(i));
@@ -363,8 +373,8 @@ public class ConcurrentSkipListSetTest extends JSR166TestCase {
assertTrue(q.removeAll(p));
assertEquals(SIZE-i, q.size());
for (int j = 0; j < i; ++j) {
- Integer I = (Integer)(p.pollFirst());
- assertFalse(q.contains(I));
+ Integer x = (Integer)(p.pollFirst());
+ assertFalse(q.contains(x));
}
}
}
@@ -467,27 +477,21 @@ public class ConcurrentSkipListSetTest extends JSR166TestCase {
*/
public void testIterator() {
ConcurrentSkipListSet q = populatedSet(SIZE);
- int i = 0;
Iterator it = q.iterator();
- while (it.hasNext()) {
+ int i;
+ for (i = 0; it.hasNext(); i++)
assertTrue(q.contains(it.next()));
- ++i;
- }
assertEquals(i, SIZE);
+ assertIteratorExhausted(it);
}
/**
* iterator of empty set has no elements
*/
public void testEmptyIterator() {
- ConcurrentSkipListSet q = new ConcurrentSkipListSet();
- int i = 0;
- Iterator it = q.iterator();
- while (it.hasNext()) {
- assertTrue(q.contains(it.next()));
- ++i;
- }
- assertEquals(0, i);
+ NavigableSet s = new ConcurrentSkipListSet();
+ assertIteratorExhausted(s.iterator());
+ assertIteratorExhausted(s.descendingSet().iterator());
}
/**
@@ -726,7 +730,7 @@ public class ConcurrentSkipListSetTest extends JSR166TestCase {
// Add entries till we're back to original size
while (set.size() < size) {
int element = min + rnd.nextInt(rangeSize);
- assertTrue(element >= min && element<= max);
+ assertTrue(element >= min && element <= max);
put(set, element, bs);
}
}
@@ -752,7 +756,7 @@ public class ConcurrentSkipListSetTest extends JSR166TestCase {
// Add entries till we're back to original size
while (set.size() < size) {
int element = min - 5 + rnd.nextInt(rangeSize + 10);
- if (element >= min && element<= max) {
+ if (element >= min && element <= max) {
put(set, element, bs);
} else {
try {
diff --git a/jsr166-tests/src/test/java/jsr166/ConcurrentSkipListSubMapTest.java b/jsr166-tests/src/test/java/jsr166/ConcurrentSkipListSubMapTest.java
index 7247657..5315bcb 100644
--- a/jsr166-tests/src/test/java/jsr166/ConcurrentSkipListSubMapTest.java
+++ b/jsr166-tests/src/test/java/jsr166/ConcurrentSkipListSubMapTest.java
@@ -6,12 +6,30 @@
package jsr166;
-import junit.framework.*;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.NavigableMap;
+import java.util.Set;
+import java.util.SortedMap;
import java.util.concurrent.ConcurrentNavigableMap;
import java.util.concurrent.ConcurrentSkipListMap;
-import java.util.*;
+
+import junit.framework.Test;
+import junit.framework.TestSuite;
public class ConcurrentSkipListSubMapTest extends JSR166TestCase {
+ // android-note: Removed because the CTS runner does a bad job of
+ // retrying tests that have suite() declarations.
+ //
+ // public static void main(String[] args) {
+ // main(suite(), args);
+ // }
+ // public static Test suite() {
+ // return new TestSuite(...);
+ // }
/**
* Returns a new map from Integers 1-5 to Strings "A"-"E".
diff --git a/jsr166-tests/src/test/java/jsr166/ConcurrentSkipListSubSetTest.java b/jsr166-tests/src/test/java/jsr166/ConcurrentSkipListSubSetTest.java
index 43c1759..f1c4aae 100644
--- a/jsr166-tests/src/test/java/jsr166/ConcurrentSkipListSubSetTest.java
+++ b/jsr166-tests/src/test/java/jsr166/ConcurrentSkipListSubSetTest.java
@@ -6,20 +6,26 @@
package jsr166;
-import junit.framework.*;
import java.util.Arrays;
-import java.util.BitSet;
-import java.util.Collection;
import java.util.Comparator;
import java.util.Iterator;
import java.util.NavigableSet;
-import java.util.NoSuchElementException;
-import java.util.Random;
-import java.util.Set;
import java.util.SortedSet;
import java.util.concurrent.ConcurrentSkipListSet;
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
public class ConcurrentSkipListSubSetTest extends JSR166TestCase {
+ // android-note: Removed because the CTS runner does a bad job of
+ // retrying tests that have suite() declarations.
+ //
+ // public static void main(String[] args) {
+ // main(suite(), args);
+ // }
+ // public static Test suite() {
+ // return new TestSuite(...);
+ // }
static class MyReverseComparator implements Comparator {
public int compare(Object x, Object y) {
@@ -36,9 +42,9 @@ public class ConcurrentSkipListSubSetTest extends JSR166TestCase {
new ConcurrentSkipListSet<Integer>();
assertTrue(q.isEmpty());
- for (int i = n-1; i >= 0; i-=2)
+ for (int i = n-1; i >= 0; i -= 2)
assertTrue(q.add(new Integer(i)));
- for (int i = (n & 1); i < n; i+=2)
+ for (int i = (n & 1); i < n; i += 2)
assertTrue(q.add(new Integer(i)));
assertTrue(q.add(new Integer(-n)));
assertTrue(q.add(new Integer(n)));
@@ -134,8 +140,8 @@ public class ConcurrentSkipListSubSetTest extends JSR166TestCase {
* add(null) throws NPE
*/
public void testAddNull() {
+ NavigableSet q = set0();
try {
- NavigableSet q = set0();
q.add(null);
shouldThrow();
} catch (NullPointerException success) {}
@@ -162,9 +168,8 @@ public class ConcurrentSkipListSubSetTest extends JSR166TestCase {
* Add of non-Comparable throws CCE
*/
public void testAddNonComparable() {
+ NavigableSet q = set0();
try {
- NavigableSet q = set0();
- q.add(new Object());
q.add(new Object());
q.add(new Object());
shouldThrow();
@@ -175,8 +180,8 @@ public class ConcurrentSkipListSubSetTest extends JSR166TestCase {
* addAll(null) throws NPE
*/
public void testAddAll1() {
+ NavigableSet q = set0();
try {
- NavigableSet q = set0();
q.addAll(null);
shouldThrow();
} catch (NullPointerException success) {}
@@ -186,9 +191,9 @@ public class ConcurrentSkipListSubSetTest extends JSR166TestCase {
* addAll of a collection with null elements throws NPE
*/
public void testAddAll2() {
+ NavigableSet q = set0();
+ Integer[] ints = new Integer[SIZE];
try {
- NavigableSet q = set0();
- Integer[] ints = new Integer[SIZE];
q.addAll(Arrays.asList(ints));
shouldThrow();
} catch (NullPointerException success) {}
@@ -199,11 +204,11 @@ public class ConcurrentSkipListSubSetTest extends JSR166TestCase {
* possibly adding some elements
*/
public void testAddAll3() {
+ NavigableSet q = set0();
+ Integer[] ints = new Integer[SIZE];
+ for (int i = 0; i < SIZE-1; ++i)
+ ints[i] = new Integer(i+SIZE);
try {
- NavigableSet q = set0();
- Integer[] ints = new Integer[SIZE];
- for (int i = 0; i < SIZE-1; ++i)
- ints[i] = new Integer(i+SIZE);
q.addAll(Arrays.asList(ints));
shouldThrow();
} catch (NullPointerException success) {}
@@ -240,13 +245,13 @@ public class ConcurrentSkipListSubSetTest extends JSR166TestCase {
*/
public void testRemoveElement() {
NavigableSet q = populatedSet(SIZE);
- for (int i = 1; i < SIZE; i+=2) {
+ for (int i = 1; i < SIZE; i += 2) {
assertTrue(q.contains(i));
assertTrue(q.remove(i));
assertFalse(q.contains(i));
assertTrue(q.contains(i-1));
}
- for (int i = 0; i < SIZE; i+=2) {
+ for (int i = 0; i < SIZE; i += 2) {
assertTrue(q.contains(i));
assertTrue(q.remove(i));
assertFalse(q.contains(i));
@@ -325,8 +330,8 @@ public class ConcurrentSkipListSubSetTest extends JSR166TestCase {
assertTrue(q.removeAll(p));
assertEquals(SIZE-i, q.size());
for (int j = 0; j < i; ++j) {
- Integer I = (Integer)(p.pollFirst());
- assertFalse(q.contains(I));
+ Integer x = (Integer)(p.pollFirst());
+ assertFalse(q.contains(x));
}
}
}
@@ -430,27 +435,19 @@ public class ConcurrentSkipListSubSetTest extends JSR166TestCase {
*/
public void testIterator() {
NavigableSet q = populatedSet(SIZE);
- int i = 0;
Iterator it = q.iterator();
- while (it.hasNext()) {
+ int i;
+ for (i = 0; it.hasNext(); i++)
assertTrue(q.contains(it.next()));
- ++i;
- }
assertEquals(i, SIZE);
+ assertIteratorExhausted(it);
}
/**
* iterator of empty set has no elements
*/
public void testEmptyIterator() {
- NavigableSet q = set0();
- int i = 0;
- Iterator it = q.iterator();
- while (it.hasNext()) {
- assertTrue(q.contains(it.next()));
- ++i;
- }
- assertEquals(0, i);
+ assertIteratorExhausted(set0().iterator());
}
/**
@@ -639,8 +636,8 @@ public class ConcurrentSkipListSubSetTest extends JSR166TestCase {
* add(null) throws NPE
*/
public void testDescendingAddNull() {
+ NavigableSet q = dset0();
try {
- NavigableSet q = dset0();
q.add(null);
shouldThrow();
} catch (NullPointerException success) {}
@@ -667,9 +664,8 @@ public class ConcurrentSkipListSubSetTest extends JSR166TestCase {
* Add of non-Comparable throws CCE
*/
public void testDescendingAddNonComparable() {
+ NavigableSet q = dset0();
try {
- NavigableSet q = dset0();
- q.add(new Object());
q.add(new Object());
q.add(new Object());
shouldThrow();
@@ -680,8 +676,8 @@ public class ConcurrentSkipListSubSetTest extends JSR166TestCase {
* addAll(null) throws NPE
*/
public void testDescendingAddAll1() {
+ NavigableSet q = dset0();
try {
- NavigableSet q = dset0();
q.addAll(null);
shouldThrow();
} catch (NullPointerException success) {}
@@ -691,9 +687,9 @@ public class ConcurrentSkipListSubSetTest extends JSR166TestCase {
* addAll of a collection with null elements throws NPE
*/
public void testDescendingAddAll2() {
+ NavigableSet q = dset0();
+ Integer[] ints = new Integer[SIZE];
try {
- NavigableSet q = dset0();
- Integer[] ints = new Integer[SIZE];
q.addAll(Arrays.asList(ints));
shouldThrow();
} catch (NullPointerException success) {}
@@ -704,11 +700,11 @@ public class ConcurrentSkipListSubSetTest extends JSR166TestCase {
* possibly adding some elements
*/
public void testDescendingAddAll3() {
+ NavigableSet q = dset0();
+ Integer[] ints = new Integer[SIZE];
+ for (int i = 0; i < SIZE-1; ++i)
+ ints[i] = new Integer(i+SIZE);
try {
- NavigableSet q = dset0();
- Integer[] ints = new Integer[SIZE];
- for (int i = 0; i < SIZE-1; ++i)
- ints[i] = new Integer(i+SIZE);
q.addAll(Arrays.asList(ints));
shouldThrow();
} catch (NullPointerException success) {}
@@ -745,10 +741,10 @@ public class ConcurrentSkipListSubSetTest extends JSR166TestCase {
*/
public void testDescendingRemoveElement() {
NavigableSet q = populatedSet(SIZE);
- for (int i = 1; i < SIZE; i+=2) {
+ for (int i = 1; i < SIZE; i += 2) {
assertTrue(q.remove(new Integer(i)));
}
- for (int i = 0; i < SIZE; i+=2) {
+ for (int i = 0; i < SIZE; i += 2 ) {
assertTrue(q.remove(new Integer(i)));
assertFalse(q.remove(new Integer(i+1)));
}
@@ -824,8 +820,8 @@ public class ConcurrentSkipListSubSetTest extends JSR166TestCase {
assertTrue(q.removeAll(p));
assertEquals(SIZE-i, q.size());
for (int j = 0; j < i; ++j) {
- Integer I = (Integer)(p.pollFirst());
- assertFalse(q.contains(I));
+ Integer x = (Integer)(p.pollFirst());
+ assertFalse(q.contains(x));
}
}
}
diff --git a/jsr166-tests/src/test/java/jsr166/CopyOnWriteArrayListTest.java b/jsr166-tests/src/test/java/jsr166/CopyOnWriteArrayListTest.java
index 6bef8be..658268a 100644
--- a/jsr166-tests/src/test/java/jsr166/CopyOnWriteArrayListTest.java
+++ b/jsr166-tests/src/test/java/jsr166/CopyOnWriteArrayListTest.java
@@ -8,7 +8,6 @@
package jsr166;
-import junit.framework.*;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
@@ -18,11 +17,23 @@ import java.util.LinkedList;
import java.util.List;
import java.util.ListIterator;
import java.util.NoSuchElementException;
-import java.util.Vector;
import java.util.concurrent.CopyOnWriteArrayList;
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
public class CopyOnWriteArrayListTest extends JSR166TestCase {
+ // android-note: Removed because the CTS runner does a bad job of
+ // retrying tests that have suite() declarations.
+ //
+ // public static void main(String[] args) {
+ // main(suite(), args);
+ // }
+ // public static Test suite() {
+ // return new TestSuite(...);
+ // }
+
static CopyOnWriteArrayList<Integer> populatedArray(int n) {
CopyOnWriteArrayList<Integer> a = new CopyOnWriteArrayList<Integer>();
assertTrue(a.isEmpty());
@@ -76,16 +87,14 @@ public class CopyOnWriteArrayListTest extends JSR166TestCase {
}
/**
- * addAll adds each element from the given collection
+ * addAll adds each element from the given collection, including duplicates
*/
public void testAddAll() {
CopyOnWriteArrayList full = populatedArray(3);
- Vector v = new Vector();
- v.add(three);
- v.add(four);
- v.add(five);
- full.addAll(v);
+ assertTrue(full.addAll(Arrays.asList(three, four, five)));
assertEquals(6, full.size());
+ assertTrue(full.addAll(Arrays.asList(three, four, five)));
+ assertEquals(9, full.size());
}
/**
@@ -94,11 +103,10 @@ public class CopyOnWriteArrayListTest extends JSR166TestCase {
*/
public void testAddAllAbsent() {
CopyOnWriteArrayList full = populatedArray(3);
- Vector v = new Vector();
- v.add(three);
- v.add(four);
- v.add(one); // will not add this element
- full.addAllAbsent(v);
+ // "one" is duplicate and will not be added
+ assertEquals(2, full.addAllAbsent(Arrays.asList(three, four, one)));
+ assertEquals(5, full.size());
+ assertEquals(0, full.addAllAbsent(Arrays.asList(three, four, one)));
assertEquals(5, full.size());
}
@@ -188,12 +196,11 @@ public class CopyOnWriteArrayListTest extends JSR166TestCase {
*/
public void testContainsAll() {
CopyOnWriteArrayList full = populatedArray(3);
- Vector v = new Vector();
- v.add(one);
- v.add(two);
- assertTrue(full.containsAll(v));
- v.add(six);
- assertFalse(full.containsAll(v));
+ assertTrue(full.containsAll(Arrays.asList()));
+ assertTrue(full.containsAll(Arrays.asList(one)));
+ assertTrue(full.containsAll(Arrays.asList(one, two)));
+ assertFalse(full.containsAll(Arrays.asList(one, two, six)));
+ assertFalse(full.containsAll(Arrays.asList(six)));
}
/**
@@ -256,11 +263,15 @@ public class CopyOnWriteArrayListTest extends JSR166TestCase {
assertTrue(it.hasNext());
assertEquals(elements[j], it.next());
}
- assertFalse(it.hasNext());
- try {
- it.next();
- shouldThrow();
- } catch (NoSuchElementException success) {}
+ assertIteratorExhausted(it);
+ }
+
+ /**
+ * iterator of empty collection has no elements
+ */
+ public void testEmptyIterator() {
+ Collection c = new CopyOnWriteArrayList();
+ assertIteratorExhausted(c.iterator());
}
/**
@@ -375,10 +386,9 @@ public class CopyOnWriteArrayListTest extends JSR166TestCase {
*/
public void testRemoveAll() {
CopyOnWriteArrayList full = populatedArray(3);
- Vector v = new Vector();
- v.add(one);
- v.add(two);
- full.removeAll(v);
+ assertTrue(full.removeAll(Arrays.asList(one, two)));
+ assertEquals(1, full.size());
+ assertFalse(full.removeAll(Arrays.asList(one, two)));
assertEquals(1, full.size());
}
@@ -494,10 +504,10 @@ public class CopyOnWriteArrayListTest extends JSR166TestCase {
* can not store the objects inside the list
*/
public void testToArray_ArrayStoreException() {
+ CopyOnWriteArrayList c = new CopyOnWriteArrayList();
+ c.add("zfasdfsdf");
+ c.add("asdadasd");
try {
- CopyOnWriteArrayList c = new CopyOnWriteArrayList();
- c.add("zfasdfsdf");
- c.add("asdadasd");
c.toArray(new Long[5]);
shouldThrow();
} catch (ArrayStoreException success) {}
@@ -507,167 +517,196 @@ public class CopyOnWriteArrayListTest extends JSR166TestCase {
* get throws an IndexOutOfBoundsException on a negative index
*/
public void testGet1_IndexOutOfBoundsException() {
- try {
- CopyOnWriteArrayList c = new CopyOnWriteArrayList();
- c.get(-1);
- shouldThrow();
- } catch (IndexOutOfBoundsException success) {}
+ CopyOnWriteArrayList c = populatedArray(5);
+ List[] lists = { c, c.subList(1, c.size() - 1) };
+ for (List list : lists) {
+ try {
+ list.get(-1);
+ shouldThrow();
+ } catch (IndexOutOfBoundsException success) {}
+ }
}
/**
* get throws an IndexOutOfBoundsException on a too high index
*/
public void testGet2_IndexOutOfBoundsException() {
- try {
- CopyOnWriteArrayList c = new CopyOnWriteArrayList();
- c.add("asdasd");
- c.add("asdad");
- c.get(100);
- shouldThrow();
- } catch (IndexOutOfBoundsException success) {}
+ CopyOnWriteArrayList c = populatedArray(5);
+ List[] lists = { c, c.subList(1, c.size() - 1) };
+ for (List list : lists) {
+ try {
+ list.get(list.size());
+ shouldThrow();
+ } catch (IndexOutOfBoundsException success) {}
+ }
}
/**
* set throws an IndexOutOfBoundsException on a negative index
*/
public void testSet1_IndexOutOfBoundsException() {
- try {
- CopyOnWriteArrayList c = new CopyOnWriteArrayList();
- c.set(-1,"qwerty");
- shouldThrow();
- } catch (IndexOutOfBoundsException success) {}
+ CopyOnWriteArrayList c = populatedArray(5);
+ List[] lists = { c, c.subList(1, c.size() - 1) };
+ for (List list : lists) {
+ try {
+ list.set(-1, "qwerty");
+ shouldThrow();
+ } catch (IndexOutOfBoundsException success) {}
+ }
}
/**
* set throws an IndexOutOfBoundsException on a too high index
*/
public void testSet2() {
- try {
- CopyOnWriteArrayList c = new CopyOnWriteArrayList();
- c.add("asdasd");
- c.add("asdad");
- c.set(100, "qwerty");
- shouldThrow();
- } catch (IndexOutOfBoundsException success) {}
+ CopyOnWriteArrayList c = populatedArray(5);
+ List[] lists = { c, c.subList(1, c.size() - 1) };
+ for (List list : lists) {
+ try {
+ list.set(list.size(), "qwerty");
+ shouldThrow();
+ } catch (IndexOutOfBoundsException success) {}
+ }
}
/**
* add throws an IndexOutOfBoundsException on a negative index
*/
public void testAdd1_IndexOutOfBoundsException() {
- try {
- CopyOnWriteArrayList c = new CopyOnWriteArrayList();
- c.add(-1,"qwerty");
- shouldThrow();
- } catch (IndexOutOfBoundsException success) {}
+ CopyOnWriteArrayList c = populatedArray(5);
+ List[] lists = { c, c.subList(1, c.size() - 1) };
+ for (List list : lists) {
+ try {
+ list.add(-1, "qwerty");
+ shouldThrow();
+ } catch (IndexOutOfBoundsException success) {}
+ }
}
/**
* add throws an IndexOutOfBoundsException on a too high index
*/
public void testAdd2_IndexOutOfBoundsException() {
- try {
- CopyOnWriteArrayList c = new CopyOnWriteArrayList();
- c.add("asdasd");
- c.add("asdasdasd");
- c.add(100, "qwerty");
- shouldThrow();
- } catch (IndexOutOfBoundsException success) {}
+ CopyOnWriteArrayList c = populatedArray(5);
+ List[] lists = { c, c.subList(1, c.size() - 1) };
+ for (List list : lists) {
+ try {
+ list.add(list.size() + 1, "qwerty");
+ shouldThrow();
+ } catch (IndexOutOfBoundsException success) {}
+ }
}
/**
* remove throws an IndexOutOfBoundsException on a negative index
*/
public void testRemove1_IndexOutOfBounds() {
- try {
- CopyOnWriteArrayList c = new CopyOnWriteArrayList();
- c.remove(-1);
- shouldThrow();
- } catch (IndexOutOfBoundsException success) {}
+ CopyOnWriteArrayList c = populatedArray(5);
+ List[] lists = { c, c.subList(1, c.size() - 1) };
+ for (List list : lists) {
+ try {
+ list.remove(-1);
+ shouldThrow();
+ } catch (IndexOutOfBoundsException success) {}
+ }
}
/**
* remove throws an IndexOutOfBoundsException on a too high index
*/
public void testRemove2_IndexOutOfBounds() {
- try {
- CopyOnWriteArrayList c = new CopyOnWriteArrayList();
- c.add("asdasd");
- c.add("adasdasd");
- c.remove(100);
- shouldThrow();
- } catch (IndexOutOfBoundsException success) {}
+ CopyOnWriteArrayList c = populatedArray(5);
+ List[] lists = { c, c.subList(1, c.size() - 1) };
+ for (List list : lists) {
+ try {
+ list.remove(list.size());
+ shouldThrow();
+ } catch (IndexOutOfBoundsException success) {}
+ }
}
/**
* addAll throws an IndexOutOfBoundsException on a negative index
*/
public void testAddAll1_IndexOutOfBoundsException() {
- try {
- CopyOnWriteArrayList c = new CopyOnWriteArrayList();
- c.addAll(-1,new LinkedList());
- shouldThrow();
- } catch (IndexOutOfBoundsException success) {}
+ CopyOnWriteArrayList c = populatedArray(5);
+ List[] lists = { c, c.subList(1, c.size() - 1) };
+ for (List list : lists) {
+ try {
+ list.addAll(-1, new LinkedList());
+ shouldThrow();
+ } catch (IndexOutOfBoundsException success) {}
+ }
}
/**
* addAll throws an IndexOutOfBoundsException on a too high index
*/
public void testAddAll2_IndexOutOfBoundsException() {
- try {
- CopyOnWriteArrayList c = new CopyOnWriteArrayList();
- c.add("asdasd");
- c.add("asdasdasd");
- c.addAll(100, new LinkedList());
- shouldThrow();
- } catch (IndexOutOfBoundsException success) {}
+ CopyOnWriteArrayList c = populatedArray(5);
+ List[] lists = { c, c.subList(1, c.size() - 1) };
+ for (List list : lists) {
+ try {
+ list.addAll(list.size() + 1, new LinkedList());
+ shouldThrow();
+ } catch (IndexOutOfBoundsException success) {}
+ }
}
/**
* listIterator throws an IndexOutOfBoundsException on a negative index
*/
public void testListIterator1_IndexOutOfBoundsException() {
- try {
- CopyOnWriteArrayList c = new CopyOnWriteArrayList();
- c.listIterator(-1);
- shouldThrow();
- } catch (IndexOutOfBoundsException success) {}
+ CopyOnWriteArrayList c = populatedArray(5);
+ List[] lists = { c, c.subList(1, c.size() - 1) };
+ for (List list : lists) {
+ try {
+ list.listIterator(-1);
+ shouldThrow();
+ } catch (IndexOutOfBoundsException success) {}
+ }
}
/**
* listIterator throws an IndexOutOfBoundsException on a too high index
*/
public void testListIterator2_IndexOutOfBoundsException() {
- try {
- CopyOnWriteArrayList c = new CopyOnWriteArrayList();
- c.add("adasd");
- c.add("asdasdas");
- c.listIterator(100);
- shouldThrow();
- } catch (IndexOutOfBoundsException success) {}
+ CopyOnWriteArrayList c = populatedArray(5);
+ List[] lists = { c, c.subList(1, c.size() - 1) };
+ for (List list : lists) {
+ try {
+ list.listIterator(list.size() + 1);
+ shouldThrow();
+ } catch (IndexOutOfBoundsException success) {}
+ }
}
/**
* subList throws an IndexOutOfBoundsException on a negative index
*/
public void testSubList1_IndexOutOfBoundsException() {
- try {
- CopyOnWriteArrayList c = new CopyOnWriteArrayList();
- c.subList(-1,100);
- shouldThrow();
- } catch (IndexOutOfBoundsException success) {}
+ CopyOnWriteArrayList c = populatedArray(5);
+ List[] lists = { c, c.subList(1, c.size() - 1) };
+ for (List list : lists) {
+ try {
+ list.subList(-1, list.size());
+ shouldThrow();
+ } catch (IndexOutOfBoundsException success) {}
+ }
}
/**
* subList throws an IndexOutOfBoundsException on a too high index
*/
public void testSubList2_IndexOutOfBoundsException() {
- try {
- CopyOnWriteArrayList c = new CopyOnWriteArrayList();
- c.add("asdasd");
- c.subList(1,100);
- shouldThrow();
- } catch (IndexOutOfBoundsException success) {}
+ CopyOnWriteArrayList c = populatedArray(5);
+ List[] lists = { c, c.subList(1, c.size() - 1) };
+ for (List list : lists) {
+ try {
+ list.subList(0, list.size() + 1);
+ shouldThrow();
+ } catch (IndexOutOfBoundsException success) {}
+ }
}
/**
@@ -675,11 +714,14 @@ public class CopyOnWriteArrayListTest extends JSR166TestCase {
* is lower then the first
*/
public void testSubList3_IndexOutOfBoundsException() {
- try {
- CopyOnWriteArrayList c = new CopyOnWriteArrayList();
- c.subList(3,1);
- shouldThrow();
- } catch (IndexOutOfBoundsException success) {}
+ CopyOnWriteArrayList c = populatedArray(5);
+ List[] lists = { c, c.subList(1, c.size() - 1) };
+ for (List list : lists) {
+ try {
+ list.subList(list.size() - 1, 1);
+ shouldThrow();
+ } catch (IndexOutOfBoundsException success) {}
+ }
}
/**
diff --git a/jsr166-tests/src/test/java/jsr166/CopyOnWriteArraySetTest.java b/jsr166-tests/src/test/java/jsr166/CopyOnWriteArraySetTest.java
index feb283f..2810802 100644
--- a/jsr166-tests/src/test/java/jsr166/CopyOnWriteArraySetTest.java
+++ b/jsr166-tests/src/test/java/jsr166/CopyOnWriteArraySetTest.java
@@ -8,7 +8,6 @@
package jsr166;
-import junit.framework.*;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
@@ -16,17 +15,28 @@ import java.util.Collections;
import java.util.Iterator;
import java.util.NoSuchElementException;
import java.util.Set;
-import java.util.Vector;
import java.util.concurrent.CopyOnWriteArraySet;
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
public class CopyOnWriteArraySetTest extends JSR166TestCase {
+ // android-note: Removed because the CTS runner does a bad job of
+ // retrying tests that have suite() declarations.
+ //
+ // public static void main(String[] args) {
+ // main(suite(), args);
+ // }
+ // public static Test suite() {
+ // return new TestSuite(...);
+ // }
static CopyOnWriteArraySet<Integer> populatedSet(int n) {
CopyOnWriteArraySet<Integer> a = new CopyOnWriteArraySet<Integer>();
assertTrue(a.isEmpty());
for (int i = 0; i < n; i++)
a.add(i);
- assertFalse(a.isEmpty());
+ assertEquals(n == 0, a.isEmpty());
assertEquals(n, a.size());
return a;
}
@@ -62,29 +72,25 @@ public class CopyOnWriteArraySetTest extends JSR166TestCase {
}
/**
- * addAll adds each element from the given collection
+ * addAll adds each non-duplicate element from the given collection
*/
public void testAddAll() {
- CopyOnWriteArraySet full = populatedSet(3);
- Vector v = new Vector();
- v.add(three);
- v.add(four);
- v.add(five);
- full.addAll(v);
+ Set full = populatedSet(3);
+ assertTrue(full.addAll(Arrays.asList(three, four, five)));
+ assertEquals(6, full.size());
+ assertFalse(full.addAll(Arrays.asList(three, four, five)));
assertEquals(6, full.size());
}
/**
- * addAll adds each element from the given collection that did not
- * already exist in the set
+ * addAll adds each non-duplicate element from the given collection
*/
public void testAddAll2() {
- CopyOnWriteArraySet full = populatedSet(3);
- Vector v = new Vector();
- v.add(three);
- v.add(four);
- v.add(one); // will not add this element
- full.addAll(v);
+ Set full = populatedSet(3);
+ // "one" is duplicate and will not be added
+ assertTrue(full.addAll(Arrays.asList(three, four, one)));
+ assertEquals(5, full.size());
+ assertFalse(full.addAll(Arrays.asList(three, four, one)));
assertEquals(5, full.size());
}
@@ -92,7 +98,7 @@ public class CopyOnWriteArraySetTest extends JSR166TestCase {
* add will not add the element if it already exists in the set
*/
public void testAdd2() {
- CopyOnWriteArraySet full = populatedSet(3);
+ Set full = populatedSet(3);
full.add(one);
assertEquals(3, full.size());
}
@@ -101,7 +107,7 @@ public class CopyOnWriteArraySetTest extends JSR166TestCase {
* add adds the element when it does not exist in the set
*/
public void testAdd3() {
- CopyOnWriteArraySet full = populatedSet(3);
+ Set full = populatedSet(3);
full.add(three);
assertTrue(full.contains(three));
}
@@ -110,16 +116,17 @@ public class CopyOnWriteArraySetTest extends JSR166TestCase {
* clear removes all elements from the set
*/
public void testClear() {
- CopyOnWriteArraySet full = populatedSet(3);
+ Collection full = populatedSet(3);
full.clear();
assertEquals(0, full.size());
+ assertTrue(full.isEmpty());
}
/**
* contains returns true for added elements
*/
public void testContains() {
- CopyOnWriteArraySet full = populatedSet(3);
+ Collection full = populatedSet(3);
assertTrue(full.contains(one));
assertFalse(full.contains(five));
}
@@ -146,23 +153,20 @@ public class CopyOnWriteArraySetTest extends JSR166TestCase {
* containsAll returns true for collections with subset of elements
*/
public void testContainsAll() {
- CopyOnWriteArraySet full = populatedSet(3);
- Vector v = new Vector();
- v.add(one);
- v.add(two);
- assertTrue(full.containsAll(v));
- v.add(six);
- assertFalse(full.containsAll(v));
+ Collection full = populatedSet(3);
+ assertTrue(full.containsAll(Arrays.asList()));
+ assertTrue(full.containsAll(Arrays.asList(one)));
+ assertTrue(full.containsAll(Arrays.asList(one, two)));
+ assertFalse(full.containsAll(Arrays.asList(one, two, six)));
+ assertFalse(full.containsAll(Arrays.asList(six)));
}
/**
* isEmpty is true when empty, else false
*/
public void testIsEmpty() {
- CopyOnWriteArraySet empty = new CopyOnWriteArraySet();
- CopyOnWriteArraySet full = populatedSet(3);
- assertTrue(empty.isEmpty());
- assertFalse(full.isEmpty());
+ assertTrue(populatedSet(0).isEmpty());
+ assertFalse(populatedSet(3).isEmpty());
}
/**
@@ -188,18 +192,21 @@ public class CopyOnWriteArraySetTest extends JSR166TestCase {
assertTrue(it.hasNext());
assertEquals(elements[j], it.next());
}
- assertFalse(it.hasNext());
- try {
- it.next();
- shouldThrow();
- } catch (NoSuchElementException success) {}
+ assertIteratorExhausted(it);
+ }
+
+ /**
+ * iterator of empty collection has no elements
+ */
+ public void testEmptyIterator() {
+ assertIteratorExhausted(new CopyOnWriteArraySet().iterator());
}
/**
* iterator remove is unsupported
*/
public void testIteratorRemove() {
- CopyOnWriteArraySet full = populatedSet(3);
+ Collection full = populatedSet(3);
Iterator it = full.iterator();
it.next();
try {
@@ -213,7 +220,7 @@ public class CopyOnWriteArraySetTest extends JSR166TestCase {
*/
public void testToString() {
assertEquals("[]", new CopyOnWriteArraySet().toString());
- CopyOnWriteArraySet full = populatedSet(3);
+ Collection full = populatedSet(3);
String s = full.toString();
for (int i = 0; i < 3; ++i)
assertTrue(s.contains(String.valueOf(i)));
@@ -225,11 +232,10 @@ public class CopyOnWriteArraySetTest extends JSR166TestCase {
* removeAll removes all elements from the given collection
*/
public void testRemoveAll() {
- CopyOnWriteArraySet full = populatedSet(3);
- Vector v = new Vector();
- v.add(one);
- v.add(two);
- full.removeAll(v);
+ Set full = populatedSet(3);
+ assertTrue(full.removeAll(Arrays.asList(one, two)));
+ assertEquals(1, full.size());
+ assertFalse(full.removeAll(Arrays.asList(one, two)));
assertEquals(1, full.size());
}
@@ -237,7 +243,7 @@ public class CopyOnWriteArraySetTest extends JSR166TestCase {
* remove removes an element
*/
public void testRemove() {
- CopyOnWriteArraySet full = populatedSet(3);
+ Collection full = populatedSet(3);
full.remove(one);
assertFalse(full.contains(one));
assertEquals(2, full.size());
@@ -247,8 +253,8 @@ public class CopyOnWriteArraySetTest extends JSR166TestCase {
* size returns the number of elements
*/
public void testSize() {
- CopyOnWriteArraySet empty = new CopyOnWriteArraySet();
- CopyOnWriteArraySet full = populatedSet(3);
+ Collection empty = new CopyOnWriteArraySet();
+ Collection full = populatedSet(3);
assertEquals(3, full.size());
assertEquals(0, empty.size());
}
diff --git a/jsr166-tests/src/test/java/jsr166/CountDownLatchTest.java b/jsr166-tests/src/test/java/jsr166/CountDownLatchTest.java
index bc2aecf..da1ebb4 100644
--- a/jsr166-tests/src/test/java/jsr166/CountDownLatchTest.java
+++ b/jsr166-tests/src/test/java/jsr166/CountDownLatchTest.java
@@ -8,12 +8,23 @@
package jsr166;
-import junit.framework.*;
-import java.util.*;
-import java.util.concurrent.CountDownLatch;
import static java.util.concurrent.TimeUnit.MILLISECONDS;
+import java.util.concurrent.CountDownLatch;
+
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
public class CountDownLatchTest extends JSR166TestCase {
+ // android-note: Removed because the CTS runner does a bad job of
+ // retrying tests that have suite() declarations.
+ //
+ // public static void main(String[] args) {
+ // main(suite(), args);
+ // }
+ // public static Test suite() {
+ // return new TestSuite(...);
+ // }
/**
* negative constructor argument throws IAE
diff --git a/jsr166-tests/src/test/java/jsr166/CountedCompleterTest.java b/jsr166-tests/src/test/java/jsr166/CountedCompleterTest.java
index 2f8665b..80d7b3b 100644
--- a/jsr166-tests/src/test/java/jsr166/CountedCompleterTest.java
+++ b/jsr166-tests/src/test/java/jsr166/CountedCompleterTest.java
@@ -6,25 +6,34 @@
package jsr166;
-import java.util.concurrent.ExecutionException;
+import static java.util.concurrent.TimeUnit.MILLISECONDS;
+import static java.util.concurrent.TimeUnit.SECONDS;
+
+import java.util.HashSet;
import java.util.concurrent.CancellationException;
+import java.util.concurrent.CountedCompleter;
+import java.util.concurrent.ExecutionException;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.ForkJoinTask;
-import java.util.concurrent.CountedCompleter;
-import java.util.concurrent.ForkJoinWorkerThread;
-import java.util.concurrent.RecursiveAction;
-import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.concurrent.atomic.AtomicInteger;
-import java.util.concurrent.atomic.AtomicIntegerFieldUpdater;
import java.util.concurrent.atomic.AtomicReference;
-import static java.util.concurrent.TimeUnit.MILLISECONDS;
-import static java.util.concurrent.TimeUnit.SECONDS;
-import java.util.HashSet;
-import junit.framework.*;
+
+import junit.framework.Test;
+import junit.framework.TestSuite;
public class CountedCompleterTest extends JSR166TestCase {
+ // android-note: Removed because the CTS runner does a bad job of
+ // retrying tests that have suite() declarations.
+ //
+ // public static void main(String[] args) {
+ // main(suite(), args);
+ // }
+ // public static Test suite() {
+ // return new TestSuite(...);
+ // }
+
// Runs with "mainPool" use > 1 thread. singletonPool tests use 1
static final int mainPoolSize =
Math.max(2, Runtime.getRuntime().availableProcessors());
@@ -193,8 +202,8 @@ public class CountedCompleterTest extends JSR166TestCase {
try {
a.invoke();
shouldThrow();
- } catch (Throwable ex) {
- assertSame(t, ex);
+ } catch (Throwable success) {
+ assertSame(t, success);
}
}
@@ -494,8 +503,9 @@ public class CountedCompleterTest extends JSR166TestCase {
// Invocation tests use some interdependent task classes
// to better test propagation etc
-
- // Version of Fibonacci with different classes for left vs right forks
+ /**
+ * Version of Fibonacci with different classes for left vs right forks
+ */
abstract class CCF extends CheckedCC {
int number;
int rnumber;
@@ -1131,7 +1141,7 @@ public class CountedCompleterTest extends JSR166TestCase {
}
/**
- * invokeAll(collection) throws exception if any task does
+ * invokeAll(collection) throws exception if any task does
*/
public void testAbnormalInvokeAllCollection() {
ForkJoinTask a = new CheckedRecursiveAction() {
@@ -1796,7 +1806,7 @@ public class CountedCompleterTest extends JSR166TestCase {
}
/**
- * invokeAll(collection) throws exception if any task does
+ * invokeAll(collection) throws exception if any task does
*/
public void testAbnormalInvokeAllCollectionSingleton() {
ForkJoinTask a = new CheckedRecursiveAction() {
diff --git a/jsr166-tests/src/test/java/jsr166/CyclicBarrierTest.java b/jsr166-tests/src/test/java/jsr166/CyclicBarrierTest.java
index 3239030..a9d8c54 100644
--- a/jsr166-tests/src/test/java/jsr166/CyclicBarrierTest.java
+++ b/jsr166-tests/src/test/java/jsr166/CyclicBarrierTest.java
@@ -8,16 +8,27 @@
package jsr166;
-import junit.framework.*;
-import java.util.*;
+import static java.util.concurrent.TimeUnit.MILLISECONDS;
+
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.TimeoutException;
import java.util.concurrent.atomic.AtomicBoolean;
-import static java.util.concurrent.TimeUnit.MILLISECONDS;
+
+import junit.framework.Test;
+import junit.framework.TestSuite;
public class CyclicBarrierTest extends JSR166TestCase {
+ // android-note: Removed because the CTS runner does a bad job of
+ // retrying tests that have suite() declarations.
+ //
+ // public static void main(String[] args) {
+ // main(suite(), args);
+ // }
+ // public static Test suite() {
+ // return new TestSuite(...);
+ // }
private volatile int countAction;
private class MyAction implements Runnable {
diff --git a/jsr166-tests/src/test/java/jsr166/DelayQueueTest.java b/jsr166-tests/src/test/java/jsr166/DelayQueueTest.java
index dc221ab..7619b48 100644
--- a/jsr166-tests/src/test/java/jsr166/DelayQueueTest.java
+++ b/jsr166-tests/src/test/java/jsr166/DelayQueueTest.java
@@ -8,9 +8,11 @@
package jsr166;
-import junit.framework.*;
-import java.util.Arrays;
+import static java.util.concurrent.TimeUnit.MILLISECONDS;
+
import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
import java.util.Iterator;
import java.util.NoSuchElementException;
import java.util.concurrent.BlockingQueue;
@@ -20,10 +22,33 @@ import java.util.concurrent.DelayQueue;
import java.util.concurrent.Executors;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.TimeUnit;
-import static java.util.concurrent.TimeUnit.MILLISECONDS;
+import junit.framework.Test;
+
+// android-changed: Extend BlockingQueueTest directly.
public class DelayQueueTest extends BlockingQueueTest {
+ // android-changed: Extend BlockingQueueTest directly instead of creating
+ // an inner class and its associated suite.
+ //
+ // public static class Generic extends BlockingQueueTest {
+ // protected BlockingQueue emptyCollection() {
+ // return new DelayQueue();
+ // }
+ // protected PDelay makeElement(int i) {
+ // return new PDelay(i);
+ // }
+ // }
+ //
+ // public static void main(String[] args) {
+ // main(suite(), args);
+ // }
+ //
+ // public static Test suite() {
+ // return newTestSuite(DelayQueueTest.class,
+ // new Generic().testSuite());
+ // }
+
protected BlockingQueue emptyCollection() {
return new DelayQueue();
}
@@ -32,8 +57,6 @@ public class DelayQueueTest extends BlockingQueueTest {
return new PDelay(i);
}
- private static final int NOCAP = Integer.MAX_VALUE;
-
/**
* A delayed implementation for testing.
* Most tests use Pseudodelays, where delays are all elapsed
@@ -115,12 +138,12 @@ public class DelayQueueTest extends BlockingQueueTest {
private DelayQueue<PDelay> populatedQueue(int n) {
DelayQueue<PDelay> q = new DelayQueue<PDelay>();
assertTrue(q.isEmpty());
- for (int i = n-1; i >= 0; i-=2)
+ for (int i = n-1; i >= 0; i -= 2)
assertTrue(q.offer(new PDelay(i)));
- for (int i = (n & 1); i < n; i+=2)
+ for (int i = (n & 1); i < n; i += 2)
assertTrue(q.offer(new PDelay(i)));
assertFalse(q.isEmpty());
- assertEquals(NOCAP, q.remainingCapacity());
+ assertEquals(Integer.MAX_VALUE, q.remainingCapacity());
assertEquals(n, q.size());
return q;
}
@@ -129,7 +152,7 @@ public class DelayQueueTest extends BlockingQueueTest {
* A new queue has unbounded capacity
*/
public void testConstructor1() {
- assertEquals(NOCAP, new DelayQueue().remainingCapacity());
+ assertEquals(Integer.MAX_VALUE, new DelayQueue().remainingCapacity());
}
/**
@@ -137,7 +160,7 @@ public class DelayQueueTest extends BlockingQueueTest {
*/
public void testConstructor3() {
try {
- DelayQueue q = new DelayQueue(null);
+ new DelayQueue(null);
shouldThrow();
} catch (NullPointerException success) {}
}
@@ -148,7 +171,7 @@ public class DelayQueueTest extends BlockingQueueTest {
public void testConstructor4() {
try {
PDelay[] ints = new PDelay[SIZE];
- DelayQueue q = new DelayQueue(Arrays.asList(ints));
+ new DelayQueue(Arrays.asList(ints));
shouldThrow();
} catch (NullPointerException success) {}
}
@@ -161,7 +184,7 @@ public class DelayQueueTest extends BlockingQueueTest {
PDelay[] ints = new PDelay[SIZE];
for (int i = 0; i < SIZE-1; ++i)
ints[i] = new PDelay(i);
- DelayQueue q = new DelayQueue(Arrays.asList(ints));
+ new DelayQueue(Arrays.asList(ints));
shouldThrow();
} catch (NullPointerException success) {}
}
@@ -184,7 +207,7 @@ public class DelayQueueTest extends BlockingQueueTest {
public void testEmpty() {
DelayQueue q = new DelayQueue();
assertTrue(q.isEmpty());
- assertEquals(NOCAP, q.remainingCapacity());
+ assertEquals(Integer.MAX_VALUE, q.remainingCapacity());
q.add(new PDelay(1));
assertFalse(q.isEmpty());
q.add(new PDelay(2));
@@ -194,20 +217,19 @@ public class DelayQueueTest extends BlockingQueueTest {
}
/**
- * remainingCapacity does not change when elements added or removed,
- * but size does
+ * remainingCapacity() always returns Integer.MAX_VALUE
*/
public void testRemainingCapacity() {
- DelayQueue q = populatedQueue(SIZE);
+ BlockingQueue q = populatedQueue(SIZE);
for (int i = 0; i < SIZE; ++i) {
- assertEquals(NOCAP, q.remainingCapacity());
+ assertEquals(Integer.MAX_VALUE, q.remainingCapacity());
assertEquals(SIZE-i, q.size());
- q.remove();
+ assertTrue(q.remove() instanceof PDelay);
}
for (int i = 0; i < SIZE; ++i) {
- assertEquals(NOCAP, q.remainingCapacity());
+ assertEquals(Integer.MAX_VALUE, q.remainingCapacity());
assertEquals(i, q.size());
- q.add(new PDelay(i));
+ assertTrue(q.add(new PDelay(i)));
}
}
@@ -278,9 +300,9 @@ public class DelayQueueTest extends BlockingQueueTest {
public void testPut() {
DelayQueue q = new DelayQueue();
for (int i = 0; i < SIZE; ++i) {
- PDelay I = new PDelay(i);
- q.put(I);
- assertTrue(q.contains(I));
+ PDelay x = new PDelay(i);
+ q.put(x);
+ assertTrue(q.contains(x));
}
assertEquals(SIZE, q.size());
}
@@ -324,7 +346,7 @@ public class DelayQueueTest extends BlockingQueueTest {
public void testTake() throws InterruptedException {
DelayQueue q = populatedQueue(SIZE);
for (int i = 0; i < SIZE; ++i) {
- assertEquals(new PDelay(i), ((PDelay)q.take()));
+ assertEquals(new PDelay(i), q.take());
}
}
@@ -367,7 +389,7 @@ public class DelayQueueTest extends BlockingQueueTest {
public void testPoll() {
DelayQueue q = populatedQueue(SIZE);
for (int i = 0; i < SIZE; ++i) {
- assertEquals(new PDelay(i), ((PDelay)q.poll()));
+ assertEquals(new PDelay(i), q.poll());
}
assertNull(q.poll());
}
@@ -378,7 +400,7 @@ public class DelayQueueTest extends BlockingQueueTest {
public void testTimedPoll0() throws InterruptedException {
DelayQueue q = populatedQueue(SIZE);
for (int i = 0; i < SIZE; ++i) {
- assertEquals(new PDelay(i), ((PDelay)q.poll(0, MILLISECONDS)));
+ assertEquals(new PDelay(i), q.poll(0, MILLISECONDS));
}
assertNull(q.poll(0, MILLISECONDS));
}
@@ -390,7 +412,7 @@ public class DelayQueueTest extends BlockingQueueTest {
DelayQueue q = populatedQueue(SIZE);
for (int i = 0; i < SIZE; ++i) {
long startTime = System.nanoTime();
- assertEquals(new PDelay(i), ((PDelay)q.poll(LONG_DELAY_MS, MILLISECONDS)));
+ assertEquals(new PDelay(i), q.poll(LONG_DELAY_MS, MILLISECONDS));
assertTrue(millisElapsedSince(startTime) < LONG_DELAY_MS);
}
long startTime = System.nanoTime();
@@ -439,8 +461,8 @@ public class DelayQueueTest extends BlockingQueueTest {
public void testPeek() {
DelayQueue q = populatedQueue(SIZE);
for (int i = 0; i < SIZE; ++i) {
- assertEquals(new PDelay(i), ((PDelay)q.peek()));
- assertEquals(new PDelay(i), ((PDelay)q.poll()));
+ assertEquals(new PDelay(i), q.peek());
+ assertEquals(new PDelay(i), q.poll());
if (q.isEmpty())
assertNull(q.peek());
else
@@ -455,7 +477,7 @@ public class DelayQueueTest extends BlockingQueueTest {
public void testElement() {
DelayQueue q = populatedQueue(SIZE);
for (int i = 0; i < SIZE; ++i) {
- assertEquals(new PDelay(i), ((PDelay)q.element()));
+ assertEquals(new PDelay(i), q.element());
q.poll();
}
try {
@@ -470,7 +492,7 @@ public class DelayQueueTest extends BlockingQueueTest {
public void testRemove() {
DelayQueue q = populatedQueue(SIZE);
for (int i = 0; i < SIZE; ++i) {
- assertEquals(new PDelay(i), ((PDelay)q.remove()));
+ assertEquals(new PDelay(i), q.remove());
}
try {
q.remove();
@@ -498,7 +520,7 @@ public class DelayQueueTest extends BlockingQueueTest {
q.clear();
assertTrue(q.isEmpty());
assertEquals(0, q.size());
- assertEquals(NOCAP, q.remainingCapacity());
+ assertEquals(Integer.MAX_VALUE, q.remainingCapacity());
PDelay x = new PDelay(1);
q.add(x);
assertFalse(q.isEmpty());
@@ -550,8 +572,8 @@ public class DelayQueueTest extends BlockingQueueTest {
assertTrue(q.removeAll(p));
assertEquals(SIZE-i, q.size());
for (int j = 0; j < i; ++j) {
- PDelay I = (PDelay)(p.remove());
- assertFalse(q.contains(I));
+ PDelay x = (PDelay)(p.remove());
+ assertFalse(q.contains(x));
}
}
}
@@ -603,6 +625,14 @@ public class DelayQueueTest extends BlockingQueueTest {
++i;
}
assertEquals(i, SIZE);
+ assertIteratorExhausted(it);
+ }
+
+ /**
+ * iterator of empty collection has no elements
+ */
+ public void testEmptyIterator() {
+ assertIteratorExhausted(new DelayQueue().iterator());
}
/**
@@ -763,4 +793,12 @@ public class DelayQueueTest extends BlockingQueueTest {
}
}
+ /**
+ * remove(null), contains(null) always return false
+ */
+ public void testNeverContainsNull() {
+ Collection<?> q = populatedQueue(SIZE);
+ assertFalse(q.contains(null));
+ assertFalse(q.remove(null));
+ }
}
diff --git a/jsr166-tests/src/test/java/jsr166/EntryTest.java b/jsr166-tests/src/test/java/jsr166/EntryTest.java
index 4387a53..d141a84 100644
--- a/jsr166-tests/src/test/java/jsr166/EntryTest.java
+++ b/jsr166-tests/src/test/java/jsr166/EntryTest.java
@@ -6,10 +6,22 @@
package jsr166;
-import junit.framework.*;
-import java.util.*;
+import java.util.AbstractMap;
+import java.util.Map;
+
+import junit.framework.Test;
+import junit.framework.TestSuite;
public class EntryTest extends JSR166TestCase {
+ // android-note: Removed because the CTS runner does a bad job of
+ // retrying tests that have suite() declarations.
+ //
+ // public static void main(String[] args) {
+ // main(suite(), args);
+ // }
+ // public static Test suite() {
+ // return new TestSuite(...);
+ // }
static final String k1 = "1";
static final String v1 = "a";
diff --git a/jsr166-tests/src/test/java/jsr166/ExchangerTest.java b/jsr166-tests/src/test/java/jsr166/ExchangerTest.java
index b0f325e..172fccd 100644
--- a/jsr166-tests/src/test/java/jsr166/ExchangerTest.java
+++ b/jsr166-tests/src/test/java/jsr166/ExchangerTest.java
@@ -8,15 +8,27 @@
package jsr166;
-import junit.framework.*;
-import java.util.*;
+import static java.util.concurrent.TimeUnit.MILLISECONDS;
+
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Exchanger;
import java.util.concurrent.TimeoutException;
-import static java.util.concurrent.TimeUnit.MILLISECONDS;
+
+import junit.framework.Test;
+import junit.framework.TestSuite;
public class ExchangerTest extends JSR166TestCase {
+ // android-note: Removed because the CTS runner does a bad job of
+ // retrying tests that have suite() declarations.
+ //
+ // public static void main(String[] args) {
+ // main(suite(), args);
+ // }
+ // public static Test suite() {
+ // return new TestSuite(...);
+ // }
+
/**
* exchange exchanges objects across two threads
*/
diff --git a/jsr166-tests/src/test/java/jsr166/ExecutorCompletionServiceTest.java b/jsr166-tests/src/test/java/jsr166/ExecutorCompletionServiceTest.java
index eced0ba..e988cc6 100644
--- a/jsr166-tests/src/test/java/jsr166/ExecutorCompletionServiceTest.java
+++ b/jsr166-tests/src/test/java/jsr166/ExecutorCompletionServiceTest.java
@@ -8,30 +8,40 @@
package jsr166;
-import junit.framework.*;
-import java.util.*;
+import static java.util.concurrent.TimeUnit.MILLISECONDS;
+
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorCompletionService;
-import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
+import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future;
import java.util.concurrent.FutureTask;
import java.util.concurrent.RunnableFuture;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
-import static java.util.concurrent.TimeUnit.MILLISECONDS;
import java.util.concurrent.atomic.AtomicBoolean;
-import java.security.*;
+
+import junit.framework.Test;
+import junit.framework.TestSuite;
public class ExecutorCompletionServiceTest extends JSR166TestCase {
+ // android-note: Removed because the CTS runner does a bad job of
+ // retrying tests that have suite() declarations.
+ //
+ // public static void main(String[] args) {
+ // main(suite(), args);
+ // }
+ // public static Test suite() {
+ // return new TestSuite(...);
+ // }
/**
* Creating a new ECS with null Executor throw NPE
*/
public void testConstructorNPE() {
try {
- ExecutorCompletionService ecs = new ExecutorCompletionService(null);
+ new ExecutorCompletionService(null);
shouldThrow();
} catch (NullPointerException success) {}
}
@@ -42,7 +52,7 @@ public class ExecutorCompletionServiceTest extends JSR166TestCase {
public void testConstructorNPE2() {
try {
ExecutorService e = Executors.newCachedThreadPool();
- ExecutorCompletionService ecs = new ExecutorCompletionService(e, null);
+ new ExecutorCompletionService(e, null);
shouldThrow();
} catch (NullPointerException success) {}
}
diff --git a/jsr166-tests/src/test/java/jsr166/ExecutorsTest.java b/jsr166-tests/src/test/java/jsr166/ExecutorsTest.java
index 18c0975..ae475f1 100644
--- a/jsr166-tests/src/test/java/jsr166/ExecutorsTest.java
+++ b/jsr166-tests/src/test/java/jsr166/ExecutorsTest.java
@@ -8,13 +8,36 @@
package jsr166;
-import junit.framework.*;
-import java.util.*;
-import java.util.concurrent.*;
import static java.util.concurrent.TimeUnit.MILLISECONDS;
-import java.security.*;
+
+import java.security.AccessControlContext;
+import java.security.AccessControlException;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.security.PrivilegedExceptionAction;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.Callable;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Future;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.ThreadPoolExecutor;
+
+import junit.framework.Test;
+import junit.framework.TestSuite;
public class ExecutorsTest extends JSR166TestCase {
+ // android-note: Removed because the CTS runner does a bad job of
+ // retrying tests that have suite() declarations.
+ //
+ // public static void main(String[] args) {
+ // main(suite(), args);
+ // }
+ // public static Test suite() {
+ // return new TestSuite(...);
+ // }
/**
* A newCachedThreadPool can execute runnables
@@ -267,7 +290,6 @@ public class ExecutorsTest extends JSR166TestCase {
for (final ExecutorService executor : executors) {
threads.add(newStartedThread(new CheckedRunnable() {
public void realRun() {
- long startTime = System.nanoTime();
Future future = executor.submit(sleeper);
assertFutureTimesOut(future);
}}));
@@ -328,7 +350,8 @@ public class ExecutorsTest extends JSR166TestCase {
public void realRun() throws Exception {
final ThreadGroup egroup = Thread.currentThread().getThreadGroup();
final ClassLoader thisccl = Thread.currentThread().getContextClassLoader();
- // final AccessControlContext thisacc = AccessController.getContext(); // Android removed
+ // android-note: Removed unsupported access controller check.
+ // final AccessControlContext thisacc = AccessController.getContext();
Runnable r = new CheckedRunnable() {
public void realRun() {
Thread current = Thread.currentThread();
@@ -343,7 +366,7 @@ public class ExecutorsTest extends JSR166TestCase {
String name = current.getName();
assertTrue(name.endsWith("thread-1"));
assertSame(thisccl, current.getContextClassLoader());
- // assertEquals(thisacc, AccessController.getContext()); // Android removed
+ // assertEquals(thisacc, AccessController.getContext());
done.countDown();
}};
ExecutorService e = Executors.newSingleThreadExecutor(Executors.privilegedThreadFactory());
diff --git a/jsr166-tests/src/test/java/jsr166/ForkJoinPoolTest.java b/jsr166-tests/src/test/java/jsr166/ForkJoinPoolTest.java
index 8416198..09a3511 100644
--- a/jsr166-tests/src/test/java/jsr166/ForkJoinPoolTest.java
+++ b/jsr166-tests/src/test/java/jsr166/ForkJoinPoolTest.java
@@ -6,34 +6,42 @@
package jsr166;
-import junit.framework.*;
+import static java.util.concurrent.TimeUnit.MILLISECONDS;
+import static java.util.concurrent.TimeUnit.NANOSECONDS;
+
+import java.security.PrivilegedAction;
+import java.security.PrivilegedExceptionAction;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
-import java.util.concurrent.Executors;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.AbstractExecutorService;
-import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Callable;
-import java.util.concurrent.Future;
+import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutionException;
-import java.util.concurrent.CancellationException;
-import java.util.concurrent.RejectedExecutionException;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ExecutorService;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.ForkJoinTask;
import java.util.concurrent.ForkJoinWorkerThread;
+import java.util.concurrent.Future;
import java.util.concurrent.RecursiveTask;
-import java.util.concurrent.TimeUnit;
+import java.util.concurrent.RejectedExecutionException;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.locks.ReentrantLock;
-import static java.util.concurrent.TimeUnit.MILLISECONDS;
-import static java.util.concurrent.TimeUnit.NANOSECONDS;
-import java.security.AccessControlException;
-import java.security.Policy;
-import java.security.PrivilegedAction;
-import java.security.PrivilegedExceptionAction;
+
+import junit.framework.AssertionFailedError;
+import junit.framework.Test;
+import junit.framework.TestSuite;
public class ForkJoinPoolTest extends JSR166TestCase {
+ // android-note: Removed because the CTS runner does a bad job of
+ // retrying tests that have suite() declarations.
+ //
+ // public static void main(String[] args) {
+ // main(suite(), args);
+ // }
+ // public static Test suite() {
+ // return new TestSuite(...);
+ // }
/*
* Testing coverage notes:
@@ -103,7 +111,7 @@ public class ForkJoinPoolTest extends JSR166TestCase {
static final class FibTask extends RecursiveTask<Integer> {
final int number;
FibTask(int n) { number = n; }
- public Integer compute() {
+ protected Integer compute() {
int n = number;
if (n <= 1)
return n;
@@ -131,7 +139,7 @@ public class ForkJoinPoolTest extends JSR166TestCase {
this.locker = locker;
this.lock = lock;
}
- public Integer compute() {
+ protected Integer compute() {
int n;
LockingFibTask f1 = null;
LockingFibTask f2 = null;
@@ -414,11 +422,10 @@ public class ForkJoinPoolTest extends JSR166TestCase {
ExecutorService e = new ForkJoinPool(1);
try {
final AtomicBoolean done = new AtomicBoolean(false);
- CheckedRunnable task = new CheckedRunnable() {
+ Future<?> future = e.submit(new CheckedRunnable() {
public void realRun() {
done.set(true);
- }};
- Future<?> future = e.submit(task);
+ }});
assertNull(future.get());
assertNull(future.get(0, MILLISECONDS));
assertTrue(done.get());
diff --git a/jsr166-tests/src/test/java/jsr166/ForkJoinTaskTest.java b/jsr166-tests/src/test/java/jsr166/ForkJoinTaskTest.java
index 080fd9c..3c1fcb7 100644
--- a/jsr166-tests/src/test/java/jsr166/ForkJoinTaskTest.java
+++ b/jsr166-tests/src/test/java/jsr166/ForkJoinTaskTest.java
@@ -6,22 +6,33 @@
package jsr166;
-import java.util.concurrent.ExecutionException;
+import static java.util.concurrent.TimeUnit.MILLISECONDS;
+import static java.util.concurrent.TimeUnit.SECONDS;
+
+import java.util.HashSet;
import java.util.concurrent.CancellationException;
+import java.util.concurrent.ExecutionException;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.ForkJoinTask;
-import java.util.concurrent.ForkJoinWorkerThread;
import java.util.concurrent.RecursiveAction;
-import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.concurrent.atomic.AtomicIntegerFieldUpdater;
-import static java.util.concurrent.TimeUnit.MILLISECONDS;
-import static java.util.concurrent.TimeUnit.SECONDS;
-import java.util.HashSet;
-import junit.framework.*;
+
+import junit.framework.Test;
+import junit.framework.TestSuite;
public class ForkJoinTaskTest extends JSR166TestCase {
+ // android-note: Removed because the CTS runner does a bad job of
+ // retrying tests that have suite() declarations.
+ //
+ // public static void main(String[] args) {
+ // main(suite(), args);
+ // }
+ // public static Test suite() {
+ // return new TestSuite(...);
+ // }
+
// Runs with "mainPool" use > 1 thread. singletonPool tests use 1
static final int mainPoolSize =
Math.max(2, Runtime.getRuntime().availableProcessors());
@@ -913,7 +924,7 @@ public class ForkJoinTaskTest extends JSR166TestCase {
}
/**
- * invokeAll(collection) throws exception if any task does
+ * invokeAll(collection) throws exception if any task does
*/
public void testAbnormalInvokeAllCollection() {
RecursiveAction a = new CheckedRecursiveAction() {
@@ -1580,7 +1591,7 @@ public class ForkJoinTaskTest extends JSR166TestCase {
}
/**
- * invokeAll(collection) throws exception if any task does
+ * invokeAll(collection) throws exception if any task does
*/
public void testAbnormalInvokeAllCollectionSingleton() {
RecursiveAction a = new CheckedRecursiveAction() {
@@ -1602,4 +1613,21 @@ public class ForkJoinTaskTest extends JSR166TestCase {
testInvokeOnPool(singletonPool(), a);
}
+ /**
+ * ForkJoinTask.quietlyComplete returns when task completes
+ * normally without setting a value. The most recent value
+ * established by setRawResult(V) (or null by default) is returned
+ * from invoke.
+ */
+ public void testQuietlyComplete() {
+ RecursiveAction a = new CheckedRecursiveAction() {
+ protected void realCompute() {
+ AsyncFib f = new AsyncFib(8);
+ f.quietlyComplete();
+ assertEquals(8, f.number);
+ checkCompletedNormally(f);
+ }};
+ testInvokeOnPool(mainPool(), a);
+ }
+
}
diff --git a/jsr166-tests/src/test/java/jsr166/FutureTaskTest.java b/jsr166-tests/src/test/java/jsr166/FutureTaskTest.java
index baab79e..a5d8c46 100644
--- a/jsr166-tests/src/test/java/jsr166/FutureTaskTest.java
+++ b/jsr166-tests/src/test/java/jsr166/FutureTaskTest.java
@@ -8,21 +8,39 @@
package jsr166;
-import junit.framework.*;
+import static java.util.concurrent.TimeUnit.MILLISECONDS;
+import static java.util.concurrent.TimeUnit.NANOSECONDS;
+import static java.util.concurrent.TimeUnit.SECONDS;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.NoSuchElementException;
import java.util.concurrent.Callable;
import java.util.concurrent.CancellationException;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutionException;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future;
import java.util.concurrent.FutureTask;
import java.util.concurrent.TimeoutException;
import java.util.concurrent.atomic.AtomicInteger;
-import static java.util.concurrent.TimeUnit.MILLISECONDS;
-import static java.util.concurrent.TimeUnit.SECONDS;
-import java.util.*;
+
+import junit.framework.Test;
+import junit.framework.TestSuite;
public class FutureTaskTest extends JSR166TestCase {
+ // android-note: Removed because the CTS runner does a bad job of
+ // retrying tests that have suite() declarations.
+ //
+ // public static void main(String[] args) {
+ // main(suite(), args);
+ // }
+ // public static Test suite() {
+ // return new TestSuite(...);
+ // }
+
void checkIsDone(Future<?> f) {
assertTrue(f.isDone());
assertFalse(f.cancel(false));
@@ -122,7 +140,7 @@ public class FutureTaskTest extends JSR166TestCase {
pf.set(new Object());
pf.setException(new Error());
for (boolean mayInterruptIfRunning : new boolean[] { true, false }) {
- pf.cancel(true);
+ pf.cancel(mayInterruptIfRunning);
}
}
@@ -473,8 +491,8 @@ public class FutureTaskTest extends JSR166TestCase {
final PublicFutureTask task =
new PublicFutureTask(new Runnable() {
public void run() {
+ pleaseCancel.countDown();
try {
- pleaseCancel.countDown();
delay(LONG_DELAY_MS);
threadShouldThrow();
} catch (InterruptedException success) {
@@ -796,4 +814,31 @@ public class FutureTaskTest extends JSR166TestCase {
}
}
+ /**
+ * timed get with most negative timeout works correctly (i.e. no
+ * underflow bug)
+ */
+ public void testGet_NegativeInfinityTimeout() throws Exception {
+ final ExecutorService pool = Executors.newFixedThreadPool(10);
+ final Runnable nop = new Runnable() { public void run() {}};
+ final FutureTask<Void> task = new FutureTask<>(nop, null);
+ final List<Future<?>> futures = new ArrayList<>();
+ Runnable r = new Runnable() { public void run() {
+ for (long timeout : new long[] { 0L, -1L, Long.MIN_VALUE }) {
+ try {
+ task.get(timeout, NANOSECONDS);
+ shouldThrow();
+ } catch (TimeoutException success) {
+ } catch (Throwable fail) {threadUnexpectedException(fail);}}}};
+ for (int i = 0; i < 10; i++)
+ futures.add(pool.submit(r));
+ try {
+ joinPool(pool);
+ for (Future<?> future : futures)
+ checkCompletedNormally(future, null);
+ } finally {
+ task.run(); // last resort to help terminate
+ }
+ }
+
}
diff --git a/jsr166-tests/src/test/java/jsr166/JSR166TestCase.java b/jsr166-tests/src/test/java/jsr166/JSR166TestCase.java
index d9bf255..61fa66d 100644
--- a/jsr166-tests/src/test/java/jsr166/JSR166TestCase.java
+++ b/jsr166-tests/src/test/java/jsr166/JSR166TestCase.java
@@ -8,31 +8,49 @@
package jsr166;
-import junit.framework.*;
+import static java.util.concurrent.TimeUnit.MILLISECONDS;
+import static java.util.concurrent.TimeUnit.NANOSECONDS;
+
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.Method;
+import java.security.CodeSource;
+import java.security.Permission;
+import java.security.PermissionCollection;
+import java.security.Permissions;
+import java.security.Policy;
+import java.security.ProtectionDomain;
+import java.security.SecurityPermission;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.Enumeration;
+import java.util.Iterator;
import java.util.List;
import java.util.NoSuchElementException;
import java.util.PropertyPermission;
-import java.util.concurrent.*;
-import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.Callable;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.CyclicBarrier;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Future;
+import java.util.concurrent.RecursiveAction;
+import java.util.concurrent.RecursiveTask;
+import java.util.concurrent.RejectedExecutionHandler;
+import java.util.concurrent.Semaphore;
+import java.util.concurrent.ThreadFactory;
+import java.util.concurrent.ThreadPoolExecutor;
+import java.util.concurrent.TimeoutException;
import java.util.concurrent.atomic.AtomicReference;
-import static java.util.concurrent.TimeUnit.MILLISECONDS;
-import static java.util.concurrent.TimeUnit.NANOSECONDS;
-import java.security.CodeSource;
-import java.security.Permission;
-import java.security.PermissionCollection;
-import java.security.Permissions;
-import java.security.Policy;
-import java.security.ProtectionDomain;
-import java.security.SecurityPermission;
+import java.util.regex.Pattern;
+
+import junit.framework.AssertionFailedError;
+import junit.framework.Test;
+import junit.framework.TestCase;
+import junit.framework.TestSuite;
/**
* Base class for JSR166 Junit TCK tests. Defines some constants,
@@ -108,6 +126,7 @@ import java.security.SecurityPermission;
* </ul>
*/
public class JSR166TestCase extends TestCase {
+ // Delays for timing-dependent tests, in milliseconds.
protected static final boolean expensiveTests = false;
@@ -116,7 +135,6 @@ public class JSR166TestCase extends TestCase {
public static long MEDIUM_DELAY_MS;
public static long LONG_DELAY_MS;
-
/**
* Returns the shortest timed delay. This could
* be reimplemented to use for example a Property.
@@ -204,7 +222,7 @@ public class JSR166TestCase extends TestCase {
}
/**
- * Find missing try { ... } finally { joinPool(e); }
+ * Finds missing try { ... } finally { joinPool(e); }
*/
void checkForkJoinPoolThreadLeaks() throws InterruptedException {
Thread[] survivors = new Thread[5];
@@ -302,11 +320,11 @@ public class JSR166TestCase extends TestCase {
public void threadAssertEquals(Object x, Object y) {
try {
assertEquals(x, y);
- } catch (AssertionFailedError t) {
- threadRecordFailure(t);
- throw t;
- } catch (Throwable t) {
- threadUnexpectedException(t);
+ } catch (AssertionFailedError fail) {
+ threadRecordFailure(fail);
+ throw fail;
+ } catch (Throwable fail) {
+ threadUnexpectedException(fail);
}
}
@@ -318,9 +336,9 @@ public class JSR166TestCase extends TestCase {
public void threadAssertSame(Object x, Object y) {
try {
assertSame(x, y);
- } catch (AssertionFailedError t) {
- threadRecordFailure(t);
- throw t;
+ } catch (AssertionFailedError fail) {
+ threadRecordFailure(fail);
+ throw fail;
}
}
@@ -385,16 +403,23 @@ public class JSR166TestCase extends TestCase {
void joinPool(ExecutorService exec) {
try {
exec.shutdown();
- assertTrue("ExecutorService did not terminate in a timely manner",
- exec.awaitTermination(2 * LONG_DELAY_MS, MILLISECONDS));
+ if (!exec.awaitTermination(2 * LONG_DELAY_MS, MILLISECONDS))
+ fail("ExecutorService " + exec +
+ " did not terminate in a timely manner");
} catch (SecurityException ok) {
// Allowed in case test doesn't have privs
- } catch (InterruptedException ie) {
+ } catch (InterruptedException fail) {
fail("Unexpected InterruptedException");
}
}
/**
+ * A debugging tool to print all stack traces, as jstack does.
+ */
+ static void printAllStackTraces() {
+ }
+
+ /**
* Checks that thread does not terminate within the default
* millisecond delay of {@code timeoutMillis()}.
*/
@@ -410,7 +435,7 @@ public class JSR166TestCase extends TestCase {
// No need to optimize the failing case via Thread.join.
delay(millis);
assertTrue(thread.isAlive());
- } catch (InterruptedException ie) {
+ } catch (InterruptedException fail) {
fail("Unexpected InterruptedException");
}
}
@@ -432,7 +457,7 @@ public class JSR166TestCase extends TestCase {
delay(millis);
for (Thread thread : threads)
assertTrue(thread.isAlive());
- } catch (InterruptedException ie) {
+ } catch (InterruptedException fail) {
fail("Unexpected InterruptedException");
}
}
@@ -454,8 +479,8 @@ public class JSR166TestCase extends TestCase {
future.get(timeoutMillis, MILLISECONDS);
shouldThrow();
} catch (TimeoutException success) {
- } catch (Exception e) {
- threadUnexpectedException(e);
+ } catch (Exception fail) {
+ threadUnexpectedException(fail);
} finally { future.cancel(true); }
assertTrue(millisElapsedSince(startTime) >= timeoutMillis);
}
@@ -499,20 +524,23 @@ public class JSR166TestCase extends TestCase {
public static final Integer m6 = new Integer(-6);
public static final Integer m10 = new Integer(-10);
-
/**
- * android-changed
- * Android does not use a SecurityManager. This will simply execute
- * the runnable ingoring permisions.
+ * Runs Runnable r with a security policy that permits precisely
+ * the specified permissions. If there is no current security
+ * manager, the runnable is run twice, both with and without a
+ * security manager. We require that any security manager permit
+ * getPolicy/setPolicy.
*/
public void runWithPermissions(Runnable r, Permission... permissions) {
r.run();
}
/**
- * android-changed
- * Android does not use a SecurityManager. This will simply execute
- * the runnable ingoring permisions.
+ * Runs Runnable r with a security policy that permits precisely
+ * the specified permissions. If there is no current security
+ * manager, a temporary one is set for the duration of the
+ * Runnable. We require that any security manager permit
+ * getPolicy/setPolicy.
*/
public void runWithSecurityManagerWithPermissions(Runnable r,
Permission... permissions) {
@@ -582,10 +610,10 @@ public class JSR166TestCase extends TestCase {
void sleep(long millis) {
try {
delay(millis);
- } catch (InterruptedException ie) {
+ } catch (InterruptedException fail) {
AssertionFailedError afe =
new AssertionFailedError("Unexpected InterruptedException");
- afe.initCause(ie);
+ afe.initCause(fail);
throw afe;
}
}
@@ -623,12 +651,42 @@ public class JSR166TestCase extends TestCase {
/**
* Returns the number of milliseconds since time given by
* startNanoTime, which must have been previously returned from a
- * call to {@link System.nanoTime()}.
+ * call to {@link System#nanoTime()}.
*/
- long millisElapsedSince(long startNanoTime) {
+ static long millisElapsedSince(long startNanoTime) {
return NANOSECONDS.toMillis(System.nanoTime() - startNanoTime);
}
+// void assertTerminatesPromptly(long timeoutMillis, Runnable r) {
+// long startTime = System.nanoTime();
+// try {
+// r.run();
+// } catch (Throwable fail) { threadUnexpectedException(fail); }
+// if (millisElapsedSince(startTime) > timeoutMillis/2)
+// throw new AssertionFailedError("did not return promptly");
+// }
+
+// void assertTerminatesPromptly(Runnable r) {
+// assertTerminatesPromptly(LONG_DELAY_MS/2, r);
+// }
+
+ /**
+ * Checks that timed f.get() returns the expected value, and does not
+ * wait for the timeout to elapse before returning.
+ */
+ <T> void checkTimedGet(Future<T> f, T expectedValue, long timeoutMillis) {
+ long startTime = System.nanoTime();
+ try {
+ assertEquals(expectedValue, f.get(timeoutMillis, MILLISECONDS));
+ } catch (Throwable fail) { threadUnexpectedException(fail); }
+ if (millisElapsedSince(startTime) > timeoutMillis/2)
+ throw new AssertionFailedError("timed get did not return promptly");
+ }
+
+ <T> void checkTimedGet(Future<T> f, T expectedValue) {
+ checkTimedGet(f, expectedValue, LONG_DELAY_MS);
+ }
+
/**
* Returns a new started daemon Thread running the given runnable.
*/
@@ -647,8 +705,8 @@ public class JSR166TestCase extends TestCase {
void awaitTermination(Thread t, long timeoutMillis) {
try {
t.join(timeoutMillis);
- } catch (InterruptedException ie) {
- threadUnexpectedException(ie);
+ } catch (InterruptedException fail) {
+ threadUnexpectedException(fail);
} finally {
if (t.getState() != Thread.State.TERMINATED) {
t.interrupt();
@@ -674,8 +732,8 @@ public class JSR166TestCase extends TestCase {
public final void run() {
try {
realRun();
- } catch (Throwable t) {
- threadUnexpectedException(t);
+ } catch (Throwable fail) {
+ threadUnexpectedException(fail);
}
}
}
@@ -729,8 +787,8 @@ public class JSR166TestCase extends TestCase {
threadShouldThrow("InterruptedException");
} catch (InterruptedException success) {
threadAssertFalse(Thread.interrupted());
- } catch (Throwable t) {
- threadUnexpectedException(t);
+ } catch (Throwable fail) {
+ threadUnexpectedException(fail);
}
}
}
@@ -741,8 +799,8 @@ public class JSR166TestCase extends TestCase {
public final T call() {
try {
return realCall();
- } catch (Throwable t) {
- threadUnexpectedException(t);
+ } catch (Throwable fail) {
+ threadUnexpectedException(fail);
return null;
}
}
@@ -759,8 +817,8 @@ public class JSR166TestCase extends TestCase {
return result;
} catch (InterruptedException success) {
threadAssertFalse(Thread.interrupted());
- } catch (Throwable t) {
- threadUnexpectedException(t);
+ } catch (Throwable fail) {
+ threadUnexpectedException(fail);
}
return null;
}
@@ -800,16 +858,16 @@ public class JSR166TestCase extends TestCase {
public void await(CountDownLatch latch) {
try {
assertTrue(latch.await(LONG_DELAY_MS, MILLISECONDS));
- } catch (Throwable t) {
- threadUnexpectedException(t);
+ } catch (Throwable fail) {
+ threadUnexpectedException(fail);
}
}
public void await(Semaphore semaphore) {
try {
assertTrue(semaphore.tryAcquire(LONG_DELAY_MS, MILLISECONDS));
- } catch (Throwable t) {
- threadUnexpectedException(t);
+ } catch (Throwable fail) {
+ threadUnexpectedException(fail);
}
}
@@ -1003,8 +1061,8 @@ public class JSR166TestCase extends TestCase {
@Override protected final void compute() {
try {
realCompute();
- } catch (Throwable t) {
- threadUnexpectedException(t);
+ } catch (Throwable fail) {
+ threadUnexpectedException(fail);
}
}
}
@@ -1018,8 +1076,8 @@ public class JSR166TestCase extends TestCase {
@Override protected final T compute() {
try {
return realCompute();
- } catch (Throwable t) {
- threadUnexpectedException(t);
+ } catch (Throwable fail) {
+ threadUnexpectedException(fail);
return null;
}
}
@@ -1043,12 +1101,12 @@ public class JSR166TestCase extends TestCase {
public int await() {
try {
return super.await(2 * LONG_DELAY_MS, MILLISECONDS);
- } catch (TimeoutException e) {
+ } catch (TimeoutException timedOut) {
throw new AssertionFailedError("timed out");
- } catch (Exception e) {
+ } catch (Exception fail) {
AssertionFailedError afe =
- new AssertionFailedError("Unexpected exception: " + e);
- afe.initCause(e);
+ new AssertionFailedError("Unexpected exception: " + fail);
+ afe.initCause(fail);
throw afe;
}
}
@@ -1076,9 +1134,7 @@ public class JSR166TestCase extends TestCase {
q.remove();
shouldThrow();
} catch (NoSuchElementException success) {}
- } catch (InterruptedException ie) {
- threadUnexpectedException(ie);
- }
+ } catch (InterruptedException fail) { threadUnexpectedException(fail); }
}
void assertSerialEquals(Object x, Object y) {
@@ -1097,8 +1153,8 @@ public class JSR166TestCase extends TestCase {
oos.flush();
oos.close();
return bos.toByteArray();
- } catch (Throwable t) {
- threadUnexpectedException(t);
+ } catch (Throwable fail) {
+ threadUnexpectedException(fail);
return new byte[0];
}
}
@@ -1111,8 +1167,8 @@ public class JSR166TestCase extends TestCase {
T clone = (T) ois.readObject();
assertSame(o.getClass(), clone.getClass());
return clone;
- } catch (Throwable t) {
- threadUnexpectedException(t);
+ } catch (Throwable fail) {
+ threadUnexpectedException(fail);
return null;
}
}
@@ -1137,4 +1193,12 @@ public class JSR166TestCase extends TestCase {
shouldThrow(expectedExceptionClass.getName());
}
}
+
+ public void assertIteratorExhausted(Iterator<?> it) {
+ try {
+ it.next();
+ shouldThrow();
+ } catch (NoSuchElementException success) {}
+ assertFalse(it.hasNext());
+ }
}
diff --git a/jsr166-tests/src/test/java/jsr166/LinkedBlockingDequeTest.java b/jsr166-tests/src/test/java/jsr166/LinkedBlockingDequeTest.java
index 4016f6d..62802bb 100644
--- a/jsr166-tests/src/test/java/jsr166/LinkedBlockingDequeTest.java
+++ b/jsr166-tests/src/test/java/jsr166/LinkedBlockingDequeTest.java
@@ -6,10 +6,12 @@
package jsr166;
-import junit.framework.*;
-import java.util.Arrays;
+import static java.util.concurrent.TimeUnit.MILLISECONDS;
+
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Collection;
+import java.util.Deque;
import java.util.Iterator;
import java.util.NoSuchElementException;
import java.util.Queue;
@@ -19,10 +21,36 @@ import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Executors;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.LinkedBlockingDeque;
-import static java.util.concurrent.TimeUnit.MILLISECONDS;
+
+import junit.framework.Test;
public class LinkedBlockingDequeTest extends JSR166TestCase {
+ // android-note: These tests have been moved into their own separate
+ // classes to work around CTS issues.
+ //
+ // public static class Unbounded extends BlockingQueueTest {
+ // protected BlockingQueue emptyCollection() {
+ // return new LinkedBlockingDeque();
+ // }
+ // }
+ //
+ // public static class Bounded extends BlockingQueueTest {
+ // protected BlockingQueue emptyCollection() {
+ // return new LinkedBlockingDeque(SIZE);
+ // }
+ // }
+ //
+ // public static void main(String[] args) {
+ // main(suite(), args);
+ // }
+ //
+ // public static Test suite() {
+ // return newTestSuite(LinkedBlockingDequeTest.class,
+ // new Unbounded().testSuite(),
+ // new Bounded().testSuite());
+ // }
+
/**
* Returns a new deque of given size containing consecutive
* Integers 0 ... n.
@@ -253,10 +281,10 @@ public class LinkedBlockingDequeTest extends JSR166TestCase {
*/
public void testRemoveFirstOccurrence() {
LinkedBlockingDeque q = populatedDeque(SIZE);
- for (int i = 1; i < SIZE; i+=2) {
+ for (int i = 1; i < SIZE; i += 2) {
assertTrue(q.removeFirstOccurrence(new Integer(i)));
}
- for (int i = 0; i < SIZE; i+=2) {
+ for (int i = 0; i < SIZE; i += 2) {
assertTrue(q.removeFirstOccurrence(new Integer(i)));
assertFalse(q.removeFirstOccurrence(new Integer(i+1)));
}
@@ -268,10 +296,10 @@ public class LinkedBlockingDequeTest extends JSR166TestCase {
*/
public void testRemoveLastOccurrence() {
LinkedBlockingDeque q = populatedDeque(SIZE);
- for (int i = 1; i < SIZE; i+=2) {
+ for (int i = 1; i < SIZE; i += 2) {
assertTrue(q.removeLastOccurrence(new Integer(i)));
}
- for (int i = 0; i < SIZE; i+=2) {
+ for (int i = 0; i < SIZE; i += 2) {
assertTrue(q.removeLastOccurrence(new Integer(i)));
assertFalse(q.removeLastOccurrence(new Integer(i+1)));
}
@@ -384,16 +412,16 @@ public class LinkedBlockingDequeTest extends JSR166TestCase {
* remainingCapacity decreases on add, increases on remove
*/
public void testRemainingCapacity() {
- LinkedBlockingDeque q = populatedDeque(SIZE);
+ BlockingQueue q = populatedDeque(SIZE);
for (int i = 0; i < SIZE; ++i) {
assertEquals(i, q.remainingCapacity());
- assertEquals(SIZE-i, q.size());
- q.remove();
+ assertEquals(SIZE, q.size() + q.remainingCapacity());
+ assertEquals(i, q.remove());
}
for (int i = 0; i < SIZE; ++i) {
assertEquals(SIZE-i, q.remainingCapacity());
- assertEquals(i, q.size());
- q.add(new Integer(i));
+ assertEquals(SIZE, q.size() + q.remainingCapacity());
+ assertTrue(q.add(i));
}
}
@@ -415,9 +443,9 @@ public class LinkedBlockingDequeTest extends JSR166TestCase {
try {
LinkedBlockingDeque q = new LinkedBlockingDeque(SIZE);
for (int i = 0; i < SIZE; ++i) {
- Integer I = new Integer(i);
- q.push(I);
- assertEquals(I, q.peek());
+ Integer x = new Integer(i);
+ q.push(x);
+ assertEquals(x, q.peek());
}
assertEquals(0, q.remainingCapacity());
q.push(new Integer(SIZE));
@@ -535,9 +563,9 @@ public class LinkedBlockingDequeTest extends JSR166TestCase {
public void testPut() throws InterruptedException {
LinkedBlockingDeque q = new LinkedBlockingDeque(SIZE);
for (int i = 0; i < SIZE; ++i) {
- Integer I = new Integer(i);
- q.put(I);
- assertTrue(q.contains(I));
+ Integer x = new Integer(i);
+ q.put(x);
+ assertTrue(q.contains(x));
}
assertEquals(0, q.remainingCapacity());
}
@@ -767,9 +795,9 @@ public class LinkedBlockingDequeTest extends JSR166TestCase {
public void testPutFirst() throws InterruptedException {
LinkedBlockingDeque q = new LinkedBlockingDeque(SIZE);
for (int i = 0; i < SIZE; ++i) {
- Integer I = new Integer(i);
- q.putFirst(I);
- assertTrue(q.contains(I));
+ Integer x = new Integer(i);
+ q.putFirst(x);
+ assertTrue(q.contains(x));
}
assertEquals(0, q.remainingCapacity());
}
@@ -1114,9 +1142,9 @@ public class LinkedBlockingDequeTest extends JSR166TestCase {
public void testPutLast() throws InterruptedException {
LinkedBlockingDeque q = new LinkedBlockingDeque(SIZE);
for (int i = 0; i < SIZE; ++i) {
- Integer I = new Integer(i);
- q.putLast(I);
- assertTrue(q.contains(I));
+ Integer x = new Integer(i);
+ q.putLast(x);
+ assertTrue(q.contains(x));
}
assertEquals(0, q.remainingCapacity());
}
@@ -1450,8 +1478,8 @@ public class LinkedBlockingDequeTest extends JSR166TestCase {
assertTrue(q.removeAll(p));
assertEquals(SIZE-i, q.size());
for (int j = 0; j < i; ++j) {
- Integer I = (Integer)(p.remove());
- assertFalse(q.contains(I));
+ Integer x = (Integer)(p.remove());
+ assertFalse(q.contains(x));
}
}
}
@@ -1495,9 +1523,26 @@ public class LinkedBlockingDequeTest extends JSR166TestCase {
public void testIterator() throws InterruptedException {
LinkedBlockingDeque q = populatedDeque(SIZE);
Iterator it = q.iterator();
- while (it.hasNext()) {
+ int i;
+ for (i = 0; it.hasNext(); i++)
+ assertTrue(q.contains(it.next()));
+ assertEquals(i, SIZE);
+ assertIteratorExhausted(it);
+
+ it = q.iterator();
+ for (i = 0; it.hasNext(); i++)
assertEquals(it.next(), q.take());
- }
+ assertEquals(i, SIZE);
+ assertIteratorExhausted(it);
+ }
+
+ /**
+ * iterator of empty collection has no elements
+ */
+ public void testEmptyIterator() {
+ Deque c = new LinkedBlockingDeque();
+ assertIteratorExhausted(c.iterator());
+ assertIteratorExhausted(c.descendingIterator());
}
/**
@@ -1750,7 +1795,24 @@ public class LinkedBlockingDequeTest extends JSR166TestCase {
assertEquals(SIZE-k, q.size());
for (int j = 0; j < k; ++j)
assertEquals(l.get(j), new Integer(j));
- while (q.poll() != null) ;
+ do {} while (q.poll() != null);
+ }
+ }
+
+ /**
+ * remove(null), contains(null) always return false
+ */
+ public void testNeverContainsNull() {
+ Deque<?>[] qs = {
+ new LinkedBlockingDeque<Object>(),
+ populatedDeque(2),
+ };
+
+ for (Deque<?> q : qs) {
+ assertFalse(q.contains(null));
+ assertFalse(q.remove(null));
+ assertFalse(q.removeFirstOccurrence(null));
+ assertFalse(q.removeLastOccurrence(null));
}
}
diff --git a/jsr166-tests/src/test/java/jsr166/LinkedBlockingQueueTest.java b/jsr166-tests/src/test/java/jsr166/LinkedBlockingQueueTest.java
index fe0b871..bd37b2a 100644
--- a/jsr166-tests/src/test/java/jsr166/LinkedBlockingQueueTest.java
+++ b/jsr166-tests/src/test/java/jsr166/LinkedBlockingQueueTest.java
@@ -8,22 +8,49 @@
package jsr166;
-import junit.framework.*;
-import java.util.Arrays;
+import static java.util.concurrent.TimeUnit.MILLISECONDS;
+
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Collection;
import java.util.Iterator;
import java.util.NoSuchElementException;
import java.util.Queue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.Executors;
import java.util.concurrent.ExecutorService;
-import static java.util.concurrent.TimeUnit.MILLISECONDS;
+import java.util.concurrent.LinkedBlockingQueue;
+
+import junit.framework.Test;
public class LinkedBlockingQueueTest extends JSR166TestCase {
+ // android-note: These tests have been moved into their own separate
+ // classes to work around CTS issues.
+ //
+ // public static class Unbounded extends BlockingQueueTest {
+ // protected BlockingQueue emptyCollection() {
+ // return new LinkedBlockingQueue();
+ // }
+ // }
+ //
+ // public static class Bounded extends BlockingQueueTest {
+ // protected BlockingQueue emptyCollection() {
+ // return new LinkedBlockingQueue(SIZE);
+ // }
+ // }
+ //
+ // public static void main(String[] args) {
+ // main(suite(), args);
+ // }
+ //
+ // public static Test suite() {
+ // return newTestSuite(LinkedBlockingQueueTest.class,
+ // new Unbounded().testSuite(),
+ // new Bounded().testSuite());
+ // }
+
/**
* Returns a new queue of given size containing consecutive
* Integers 0 ... n.
@@ -126,16 +153,16 @@ public class LinkedBlockingQueueTest extends JSR166TestCase {
* remainingCapacity decreases on add, increases on remove
*/
public void testRemainingCapacity() {
- LinkedBlockingQueue q = populatedQueue(SIZE);
+ BlockingQueue q = populatedQueue(SIZE);
for (int i = 0; i < SIZE; ++i) {
assertEquals(i, q.remainingCapacity());
- assertEquals(SIZE-i, q.size());
- q.remove();
+ assertEquals(SIZE, q.size() + q.remainingCapacity());
+ assertEquals(i, q.remove());
}
for (int i = 0; i < SIZE; ++i) {
assertEquals(SIZE-i, q.remainingCapacity());
- assertEquals(i, q.size());
- q.add(new Integer(i));
+ assertEquals(SIZE, q.size() + q.remainingCapacity());
+ assertTrue(q.add(i));
}
}
@@ -225,9 +252,9 @@ public class LinkedBlockingQueueTest extends JSR166TestCase {
public void testPut() throws InterruptedException {
LinkedBlockingQueue q = new LinkedBlockingQueue(SIZE);
for (int i = 0; i < SIZE; ++i) {
- Integer I = new Integer(i);
- q.put(I);
- assertTrue(q.contains(I));
+ Integer x = new Integer(i);
+ q.put(x);
+ assertTrue(q.contains(x));
}
assertEquals(0, q.remainingCapacity());
}
@@ -567,8 +594,8 @@ public class LinkedBlockingQueueTest extends JSR166TestCase {
assertTrue(q.removeAll(p));
assertEquals(SIZE-i, q.size());
for (int j = 0; j < i; ++j) {
- Integer I = (Integer)(p.remove());
- assertFalse(q.contains(I));
+ Integer x = (Integer)(p.remove());
+ assertFalse(q.contains(x));
}
}
}
@@ -612,9 +639,24 @@ public class LinkedBlockingQueueTest extends JSR166TestCase {
public void testIterator() throws InterruptedException {
LinkedBlockingQueue q = populatedQueue(SIZE);
Iterator it = q.iterator();
- while (it.hasNext()) {
+ int i;
+ for (i = 0; it.hasNext(); i++)
+ assertTrue(q.contains(it.next()));
+ assertEquals(i, SIZE);
+ assertIteratorExhausted(it);
+
+ it = q.iterator();
+ for (i = 0; it.hasNext(); i++)
assertEquals(it.next(), q.take());
- }
+ assertEquals(i, SIZE);
+ assertIteratorExhausted(it);
+ }
+
+ /**
+ * iterator of empty collection has no elements
+ */
+ public void testEmptyIterator() {
+ assertIteratorExhausted(new LinkedBlockingQueue().iterator());
}
/**
@@ -805,7 +847,22 @@ public class LinkedBlockingQueueTest extends JSR166TestCase {
assertEquals(SIZE-k, q.size());
for (int j = 0; j < k; ++j)
assertEquals(l.get(j), new Integer(j));
- while (q.poll() != null) ;
+ do {} while (q.poll() != null);
+ }
+ }
+
+ /**
+ * remove(null), contains(null) always return false
+ */
+ public void testNeverContainsNull() {
+ Collection<?>[] qs = {
+ new LinkedBlockingQueue<Object>(),
+ populatedQueue(2),
+ };
+
+ for (Collection<?> q : qs) {
+ assertFalse(q.contains(null));
+ assertFalse(q.remove(null));
}
}
diff --git a/jsr166-tests/src/test/java/jsr166/LinkedListTest.java b/jsr166-tests/src/test/java/jsr166/LinkedListTest.java
index 5b09100..9d9481d 100644
--- a/jsr166-tests/src/test/java/jsr166/LinkedListTest.java
+++ b/jsr166-tests/src/test/java/jsr166/LinkedListTest.java
@@ -8,14 +8,25 @@
package jsr166;
-import junit.framework.*;
import java.util.Arrays;
import java.util.Collection;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.NoSuchElementException;
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
public class LinkedListTest extends JSR166TestCase {
+ // android-note: Removed because the CTS runner does a bad job of
+ // retrying tests that have suite() declarations.
+ //
+ // public static void main(String[] args) {
+ // main(suite(), args);
+ // }
+ // public static Test suite() {
+ // return new TestSuite(...);
+ // }
/**
* Returns a new queue of given size containing consecutive
@@ -43,7 +54,7 @@ public class LinkedListTest extends JSR166TestCase {
*/
public void testConstructor3() {
try {
- LinkedList q = new LinkedList((Collection)null);
+ new LinkedList((Collection)null);
shouldThrow();
} catch (NullPointerException success) {}
}
@@ -230,13 +241,13 @@ public class LinkedListTest extends JSR166TestCase {
*/
public void testRemoveElement() {
LinkedList q = populatedQueue(SIZE);
- for (int i = 1; i < SIZE; i+=2) {
+ for (int i = 1; i < SIZE; i += 2) {
assertTrue(q.contains(i));
assertTrue(q.remove((Integer)i));
assertFalse(q.contains(i));
assertTrue(q.contains(i-1));
}
- for (int i = 0; i < SIZE; i+=2) {
+ for (int i = 0; i < SIZE; i += 2) {
assertTrue(q.contains(i));
assertTrue(q.remove((Integer)i));
assertFalse(q.contains(i));
@@ -315,8 +326,8 @@ public class LinkedListTest extends JSR166TestCase {
assertTrue(q.removeAll(p));
assertEquals(SIZE-i, q.size());
for (int j = 0; j < i; ++j) {
- Integer I = (Integer)(p.remove());
- assertFalse(q.contains(I));
+ Integer x = (Integer)(p.remove());
+ assertFalse(q.contains(x));
}
}
}
@@ -372,13 +383,19 @@ public class LinkedListTest extends JSR166TestCase {
*/
public void testIterator() {
LinkedList q = populatedQueue(SIZE);
- int i = 0;
Iterator it = q.iterator();
- while (it.hasNext()) {
+ int i;
+ for (i = 0; it.hasNext(); i++)
assertTrue(q.contains(it.next()));
- ++i;
- }
assertEquals(i, SIZE);
+ assertIteratorExhausted(it);
+ }
+
+ /**
+ * iterator of empty collection has no elements
+ */
+ public void testEmptyIterator() {
+ assertIteratorExhausted(new LinkedList().iterator());
}
/**
@@ -599,10 +616,10 @@ public class LinkedListTest extends JSR166TestCase {
*/
public void testRemoveFirstOccurrence() {
LinkedList q = populatedQueue(SIZE);
- for (int i = 1; i < SIZE; i+=2) {
+ for (int i = 1; i < SIZE; i += 2) {
assertTrue(q.removeFirstOccurrence(new Integer(i)));
}
- for (int i = 0; i < SIZE; i+=2) {
+ for (int i = 0; i < SIZE; i += 2) {
assertTrue(q.removeFirstOccurrence(new Integer(i)));
assertFalse(q.removeFirstOccurrence(new Integer(i+1)));
}
@@ -614,10 +631,10 @@ public class LinkedListTest extends JSR166TestCase {
*/
public void testRemoveLastOccurrence() {
LinkedList q = populatedQueue(SIZE);
- for (int i = 1; i < SIZE; i+=2) {
+ for (int i = 1; i < SIZE; i += 2) {
assertTrue(q.removeLastOccurrence(new Integer(i)));
}
- for (int i = 0; i < SIZE; i+=2) {
+ for (int i = 0; i < SIZE; i += 2) {
assertTrue(q.removeLastOccurrence(new Integer(i)));
assertFalse(q.removeLastOccurrence(new Integer(i+1)));
}
diff --git a/jsr166-tests/src/test/java/jsr166/LinkedTransferQueueTest.java b/jsr166-tests/src/test/java/jsr166/LinkedTransferQueueTest.java
index 94427df..f5893ec 100644
--- a/jsr166-tests/src/test/java/jsr166/LinkedTransferQueueTest.java
+++ b/jsr166-tests/src/test/java/jsr166/LinkedTransferQueueTest.java
@@ -7,9 +7,10 @@
package jsr166;
-import junit.framework.*;
-import java.util.Arrays;
+import static java.util.concurrent.TimeUnit.MILLISECONDS;
+
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
@@ -20,12 +21,30 @@ import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Executors;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.LinkedTransferQueue;
-import static java.util.concurrent.TimeUnit.MILLISECONDS;
-import static java.util.concurrent.TimeUnit.NANOSECONDS;
+
+import junit.framework.Test;
@SuppressWarnings({"unchecked", "rawtypes"})
+// android-changed: Extend BlockingQueueTest directly.
public class LinkedTransferQueueTest extends BlockingQueueTest {
+ // android-changed: Extend BlockingQueueTest directly.
+ //
+ // public static class Generic extends BlockingQueueTest {
+ // protected BlockingQueue emptyCollection() {
+ // return new LinkedTransferQueue();
+ // }
+ // }
+ //
+ // public static void main(String[] args) {
+ // main(suite(), args);
+ // }
+ //
+ // public static Test suite() {
+ // return newTestSuite(LinkedTransferQueueTest.class,
+ // new Generic().testSuite());
+ // }
+
protected BlockingQueue emptyCollection() {
return new LinkedTransferQueue();
}
@@ -105,16 +124,16 @@ public class LinkedTransferQueueTest extends BlockingQueueTest {
* remainingCapacity() always returns Integer.MAX_VALUE
*/
public void testRemainingCapacity() {
- LinkedTransferQueue<Integer> q = populatedQueue(SIZE);
+ BlockingQueue q = populatedQueue(SIZE);
for (int i = 0; i < SIZE; ++i) {
assertEquals(Integer.MAX_VALUE, q.remainingCapacity());
assertEquals(SIZE - i, q.size());
- q.remove();
+ assertEquals(i, q.remove());
}
for (int i = 0; i < SIZE; ++i) {
assertEquals(Integer.MAX_VALUE, q.remainingCapacity());
assertEquals(i, q.size());
- q.add(i);
+ assertTrue(q.add(i));
}
}
@@ -490,11 +509,24 @@ public class LinkedTransferQueueTest extends BlockingQueueTest {
public void testIterator() throws InterruptedException {
LinkedTransferQueue q = populatedQueue(SIZE);
Iterator it = q.iterator();
- int i = 0;
- while (it.hasNext()) {
- assertEquals(it.next(), i++);
- }
+ int i;
+ for (i = 0; it.hasNext(); i++)
+ assertTrue(q.contains(it.next()));
+ assertEquals(i, SIZE);
+ assertIteratorExhausted(it);
+
+ it = q.iterator();
+ for (i = 0; it.hasNext(); i++)
+ assertEquals(it.next(), q.take());
assertEquals(i, SIZE);
+ assertIteratorExhausted(it);
+ }
+
+ /**
+ * iterator of empty collection has no elements
+ */
+ public void testEmptyIterator() {
+ assertIteratorExhausted(new LinkedTransferQueue().iterator());
}
/**
@@ -687,8 +719,7 @@ public class LinkedTransferQueueTest extends BlockingQueueTest {
assertEquals(SIZE - k, q.size());
for (int j = 0; j < k; ++j)
assertEquals(j, l.get(j));
- while (q.poll() != null)
- ;
+ do {} while (q.poll() != null);
}
}
@@ -1004,4 +1035,19 @@ public class LinkedTransferQueueTest extends BlockingQueueTest {
assertFalse(q.isEmpty());
return q;
}
+
+ /**
+ * remove(null), contains(null) always return false
+ */
+ public void testNeverContainsNull() {
+ Collection<?>[] qs = {
+ new LinkedTransferQueue<Object>(),
+ populatedQueue(2),
+ };
+
+ for (Collection<?> q : qs) {
+ assertFalse(q.contains(null));
+ assertFalse(q.remove(null));
+ }
+ }
}
diff --git a/jsr166-tests/src/test/java/jsr166/LockSupportTest.java b/jsr166-tests/src/test/java/jsr166/LockSupportTest.java
index 051de35..8347b08 100644
--- a/jsr166-tests/src/test/java/jsr166/LockSupportTest.java
+++ b/jsr166-tests/src/test/java/jsr166/LockSupportTest.java
@@ -9,13 +9,25 @@
package jsr166;
-import junit.framework.*;
+import static java.util.concurrent.TimeUnit.MILLISECONDS;
+
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.locks.LockSupport;
-import static java.util.concurrent.TimeUnit.MILLISECONDS;
+
+import junit.framework.Test;
+import junit.framework.TestSuite;
public class LockSupportTest extends JSR166TestCase {
+ // android-note: Removed because the CTS runner does a bad job of
+ // retrying tests that have suite() declarations.
+ //
+ // public static void main(String[] args) {
+ // main(suite(), args);
+ // }
+ // public static Test suite() {
+ // return new TestSuite(...);
+ // }
/**
* Returns the blocker object used by tests in this file.
diff --git a/jsr166-tests/src/test/java/jsr166/PhaserTest.java b/jsr166-tests/src/test/java/jsr166/PhaserTest.java
index 3889c1f..42d72f4 100644
--- a/jsr166-tests/src/test/java/jsr166/PhaserTest.java
+++ b/jsr166-tests/src/test/java/jsr166/PhaserTest.java
@@ -7,19 +7,30 @@
package jsr166;
-import junit.framework.*;
+import static java.util.concurrent.TimeUnit.MILLISECONDS;
+
import java.util.ArrayList;
import java.util.List;
-import java.util.concurrent.Phaser;
import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.Phaser;
import java.util.concurrent.TimeoutException;
-import static java.util.concurrent.TimeUnit.MILLISECONDS;
-import static java.util.concurrent.TimeUnit.NANOSECONDS;
-import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
public class PhaserTest extends JSR166TestCase {
+ // android-note: Removed because the CTS runner does a bad job of
+ // retrying tests that have suite() declarations.
+ //
+ // public static void main(String[] args) {
+ // main(suite(), args);
+ // }
+ // public static Test suite() {
+ // return new TestSuite(...);
+ // }
+
private static final int maxParties = 65535;
/** Checks state of unterminated phaser. */
diff --git a/jsr166-tests/src/test/java/jsr166/PriorityBlockingQueueTest.java b/jsr166-tests/src/test/java/jsr166/PriorityBlockingQueueTest.java
index 89d6d24..64c3b3a 100644
--- a/jsr166-tests/src/test/java/jsr166/PriorityBlockingQueueTest.java
+++ b/jsr166-tests/src/test/java/jsr166/PriorityBlockingQueueTest.java
@@ -8,24 +8,49 @@
package jsr166;
-import junit.framework.*;
-import java.util.Arrays;
+import static java.util.concurrent.TimeUnit.MILLISECONDS;
+
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Collection;
import java.util.Comparator;
import java.util.Iterator;
import java.util.NoSuchElementException;
import java.util.Queue;
-import java.util.concurrent.PriorityBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Executors;
import java.util.concurrent.ExecutorService;
-import static java.util.concurrent.TimeUnit.MILLISECONDS;
+import java.util.concurrent.PriorityBlockingQueue;
+
+import junit.framework.Test;
public class PriorityBlockingQueueTest extends JSR166TestCase {
- private static final int NOCAP = Integer.MAX_VALUE;
+ // android-note: These tests have been moved into their own separate
+ // classes to work around CTS issues.
+ //
+ // public static class Generic extends BlockingQueueTest {
+ // protected BlockingQueue emptyCollection() {
+ // return new PriorityBlockingQueue();
+ // }
+ // }
+ //
+ // public static class InitialCapacity extends BlockingQueueTest {
+ // protected BlockingQueue emptyCollection() {
+ // return new PriorityBlockingQueue(SIZE);
+ // }
+ // }
+ //
+ // public static void main(String[] args) {
+ // main(suite(), args);
+ // }
+ //
+ // public static Test suite() {
+ // return newTestSuite(PriorityBlockingQueueTest.class,
+ // new Generic().testSuite(),
+ // new InitialCapacity().testSuite());
+ // }
/** Sample Comparator */
static class MyReverseComparator implements Comparator {
@@ -42,12 +67,12 @@ public class PriorityBlockingQueueTest extends JSR166TestCase {
PriorityBlockingQueue<Integer> q =
new PriorityBlockingQueue<Integer>(n);
assertTrue(q.isEmpty());
- for (int i = n-1; i >= 0; i-=2)
+ for (int i = n-1; i >= 0; i -= 2)
assertTrue(q.offer(new Integer(i)));
- for (int i = (n & 1); i < n; i+=2)
+ for (int i = (n & 1); i < n; i += 2)
assertTrue(q.offer(new Integer(i)));
assertFalse(q.isEmpty());
- assertEquals(NOCAP, q.remainingCapacity());
+ assertEquals(Integer.MAX_VALUE, q.remainingCapacity());
assertEquals(n, q.size());
return q;
}
@@ -56,7 +81,8 @@ public class PriorityBlockingQueueTest extends JSR166TestCase {
* A new queue has unbounded capacity
*/
public void testConstructor1() {
- assertEquals(NOCAP, new PriorityBlockingQueue(SIZE).remainingCapacity());
+ assertEquals(Integer.MAX_VALUE,
+ new PriorityBlockingQueue(SIZE).remainingCapacity());
}
/**
@@ -137,7 +163,7 @@ public class PriorityBlockingQueueTest extends JSR166TestCase {
public void testEmpty() {
PriorityBlockingQueue q = new PriorityBlockingQueue(2);
assertTrue(q.isEmpty());
- assertEquals(NOCAP, q.remainingCapacity());
+ assertEquals(Integer.MAX_VALUE, q.remainingCapacity());
q.add(one);
assertFalse(q.isEmpty());
q.add(two);
@@ -147,20 +173,19 @@ public class PriorityBlockingQueueTest extends JSR166TestCase {
}
/**
- * remainingCapacity does not change when elements added or removed,
- * but size does
+ * remainingCapacity() always returns Integer.MAX_VALUE
*/
public void testRemainingCapacity() {
- PriorityBlockingQueue q = populatedQueue(SIZE);
+ BlockingQueue q = populatedQueue(SIZE);
for (int i = 0; i < SIZE; ++i) {
- assertEquals(NOCAP, q.remainingCapacity());
- assertEquals(SIZE-i, q.size());
- q.remove();
+ assertEquals(Integer.MAX_VALUE, q.remainingCapacity());
+ assertEquals(SIZE - i, q.size());
+ assertEquals(i, q.remove());
}
for (int i = 0; i < SIZE; ++i) {
- assertEquals(NOCAP, q.remainingCapacity());
+ assertEquals(Integer.MAX_VALUE, q.remainingCapacity());
assertEquals(i, q.size());
- q.add(new Integer(i));
+ assertTrue(q.add(i));
}
}
@@ -177,9 +202,8 @@ public class PriorityBlockingQueueTest extends JSR166TestCase {
* Offer of non-Comparable throws CCE
*/
public void testOfferNonComparable() {
+ PriorityBlockingQueue q = new PriorityBlockingQueue(1);
try {
- PriorityBlockingQueue q = new PriorityBlockingQueue(1);
- q.offer(new Object());
q.offer(new Object());
q.offer(new Object());
shouldThrow();
@@ -244,9 +268,9 @@ public class PriorityBlockingQueueTest extends JSR166TestCase {
public void testPut() {
PriorityBlockingQueue q = new PriorityBlockingQueue(SIZE);
for (int i = 0; i < SIZE; ++i) {
- Integer I = new Integer(i);
- q.put(I);
- assertTrue(q.contains(I));
+ Integer x = new Integer(i);
+ q.put(x);
+ assertTrue(q.contains(x));
}
assertEquals(SIZE, q.size());
}
@@ -508,8 +532,8 @@ public class PriorityBlockingQueueTest extends JSR166TestCase {
assertTrue(q.removeAll(p));
assertEquals(SIZE-i, q.size());
for (int j = 0; j < i; ++j) {
- Integer I = (Integer)(p.remove());
- assertFalse(q.contains(I));
+ Integer x = (Integer)(p.remove());
+ assertFalse(q.contains(x));
}
}
}
@@ -554,13 +578,19 @@ public class PriorityBlockingQueueTest extends JSR166TestCase {
*/
public void testIterator() {
PriorityBlockingQueue q = populatedQueue(SIZE);
- int i = 0;
Iterator it = q.iterator();
- while (it.hasNext()) {
+ int i;
+ for (i = 0; it.hasNext(); i++)
assertTrue(q.contains(it.next()));
- ++i;
- }
assertEquals(i, SIZE);
+ assertIteratorExhausted(it);
+ }
+
+ /**
+ * iterator of empty collection has no elements
+ */
+ public void testEmptyIterator() {
+ assertIteratorExhausted(new PriorityBlockingQueue().iterator());
}
/**
@@ -692,7 +722,22 @@ public class PriorityBlockingQueueTest extends JSR166TestCase {
assertEquals(SIZE-k, q.size());
for (int j = 0; j < k; ++j)
assertEquals(l.get(j), new Integer(j));
- while (q.poll() != null) ;
+ do {} while (q.poll() != null);
+ }
+ }
+
+ /**
+ * remove(null), contains(null) always return false
+ */
+ public void testNeverContainsNull() {
+ Collection<?>[] qs = {
+ new PriorityBlockingQueue<Object>(),
+ populatedQueue(2),
+ };
+
+ for (Collection<?> q : qs) {
+ assertFalse(q.contains(null));
+ assertFalse(q.remove(null));
}
}
diff --git a/jsr166-tests/src/test/java/jsr166/PriorityQueueTest.java b/jsr166-tests/src/test/java/jsr166/PriorityQueueTest.java
index 2b237dd..88cdd37 100644
--- a/jsr166-tests/src/test/java/jsr166/PriorityQueueTest.java
+++ b/jsr166-tests/src/test/java/jsr166/PriorityQueueTest.java
@@ -8,7 +8,6 @@
package jsr166;
-import junit.framework.*;
import java.util.Arrays;
import java.util.Collection;
import java.util.Comparator;
@@ -17,7 +16,19 @@ import java.util.NoSuchElementException;
import java.util.PriorityQueue;
import java.util.Queue;
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
public class PriorityQueueTest extends JSR166TestCase {
+ // android-note: Removed because the CTS runner does a bad job of
+ // retrying tests that have suite() declarations.
+ //
+ // public static void main(String[] args) {
+ // main(suite(), args);
+ // }
+ // public static Test suite() {
+ // return new TestSuite(...);
+ // }
static class MyReverseComparator implements Comparator {
public int compare(Object x, Object y) {
@@ -32,9 +43,9 @@ public class PriorityQueueTest extends JSR166TestCase {
private PriorityQueue<Integer> populatedQueue(int n) {
PriorityQueue<Integer> q = new PriorityQueue<Integer>(n);
assertTrue(q.isEmpty());
- for (int i = n-1; i >= 0; i-=2)
+ for (int i = n-1; i >= 0; i -= 2)
assertTrue(q.offer(new Integer(i)));
- for (int i = (n & 1); i < n; i+=2)
+ for (int i = (n & 1); i < n; i += 2)
assertTrue(q.offer(new Integer(i)));
assertFalse(q.isEmpty());
assertEquals(n, q.size());
@@ -53,7 +64,7 @@ public class PriorityQueueTest extends JSR166TestCase {
*/
public void testConstructor2() {
try {
- PriorityQueue q = new PriorityQueue(0);
+ new PriorityQueue(0);
shouldThrow();
} catch (IllegalArgumentException success) {}
}
@@ -63,7 +74,7 @@ public class PriorityQueueTest extends JSR166TestCase {
*/
public void testConstructor3() {
try {
- PriorityQueue q = new PriorityQueue((Collection)null);
+ new PriorityQueue((Collection)null);
shouldThrow();
} catch (NullPointerException success) {}
}
@@ -74,7 +85,7 @@ public class PriorityQueueTest extends JSR166TestCase {
public void testConstructor4() {
try {
Integer[] ints = new Integer[SIZE];
- PriorityQueue q = new PriorityQueue(Arrays.asList(ints));
+ new PriorityQueue(Arrays.asList(ints));
shouldThrow();
} catch (NullPointerException success) {}
}
@@ -87,7 +98,7 @@ public class PriorityQueueTest extends JSR166TestCase {
Integer[] ints = new Integer[SIZE];
for (int i = 0; i < SIZE-1; ++i)
ints[i] = new Integer(i);
- PriorityQueue q = new PriorityQueue(Arrays.asList(ints));
+ new PriorityQueue(Arrays.asList(ints));
shouldThrow();
} catch (NullPointerException success) {}
}
@@ -183,9 +194,8 @@ public class PriorityQueueTest extends JSR166TestCase {
* Offer of non-Comparable throws CCE
*/
public void testOfferNonComparable() {
+ PriorityQueue q = new PriorityQueue(1);
try {
- PriorityQueue q = new PriorityQueue(1);
- q.offer(new Object());
q.offer(new Object());
q.offer(new Object());
shouldThrow();
@@ -315,13 +325,13 @@ public class PriorityQueueTest extends JSR166TestCase {
*/
public void testRemoveElement() {
PriorityQueue q = populatedQueue(SIZE);
- for (int i = 1; i < SIZE; i+=2) {
+ for (int i = 1; i < SIZE; i += 2) {
assertTrue(q.contains(i));
assertTrue(q.remove(i));
assertFalse(q.contains(i));
assertTrue(q.contains(i-1));
}
- for (int i = 0; i < SIZE; i+=2) {
+ for (int i = 0; i < SIZE; i += 2) {
assertTrue(q.contains(i));
assertTrue(q.remove(i));
assertFalse(q.contains(i));
@@ -400,8 +410,8 @@ public class PriorityQueueTest extends JSR166TestCase {
assertTrue(q.removeAll(p));
assertEquals(SIZE-i, q.size());
for (int j = 0; j < i; ++j) {
- Integer I = (Integer)(p.remove());
- assertFalse(q.contains(I));
+ Integer x = (Integer)(p.remove());
+ assertFalse(q.contains(x));
}
}
}
@@ -435,13 +445,19 @@ public class PriorityQueueTest extends JSR166TestCase {
*/
public void testIterator() {
PriorityQueue q = populatedQueue(SIZE);
- int i = 0;
Iterator it = q.iterator();
- while (it.hasNext()) {
+ int i;
+ for (i = 0; it.hasNext(); i++)
assertTrue(q.contains(it.next()));
- ++i;
- }
assertEquals(i, SIZE);
+ assertIteratorExhausted(it);
+ }
+
+ /**
+ * iterator of empty collection has no elements
+ */
+ public void testEmptyIterator() {
+ assertIteratorExhausted(new PriorityQueue().iterator());
}
/**
diff --git a/jsr166-tests/src/test/java/jsr166/RecursiveActionTest.java b/jsr166-tests/src/test/java/jsr166/RecursiveActionTest.java
index ad61a2e..1c3bba8 100644
--- a/jsr166-tests/src/test/java/jsr166/RecursiveActionTest.java
+++ b/jsr166-tests/src/test/java/jsr166/RecursiveActionTest.java
@@ -6,23 +6,35 @@
package jsr166;
-import junit.framework.*;
+import static java.util.concurrent.TimeUnit.SECONDS;
+
+import java.util.Arrays;
+import java.util.HashSet;
import java.util.concurrent.CancellationException;
-import java.util.concurrent.SynchronousQueue;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.ForkJoinTask;
import java.util.concurrent.ForkJoinWorkerThread;
import java.util.concurrent.RecursiveAction;
+import java.util.concurrent.SynchronousQueue;
import java.util.concurrent.ThreadLocalRandom;
-import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
-import static java.util.concurrent.TimeUnit.SECONDS;
-import java.util.Arrays;
-import java.util.HashSet;
+
+import junit.framework.Test;
+import junit.framework.TestSuite;
public class RecursiveActionTest extends JSR166TestCase {
+ // android-note: Removed because the CTS runner does a bad job of
+ // retrying tests that have suite() declarations.
+ //
+ // public static void main(String[] args) {
+ // main(suite(), args);
+ // }
+ // public static Test suite() {
+ // return new TestSuite(...);
+ // }
+
private static ForkJoinPool mainPool() {
return new ForkJoinPool();
}
@@ -496,6 +508,8 @@ public class RecursiveActionTest extends JSR166TestCase {
FibAction f = new FibAction(8);
assertSame(f, f.fork());
helpQuiesce();
+ while (!f.isDone()) // wait out race
+ ;
assertEquals(21, f.result);
assertEquals(0, getQueuedTaskCount());
checkCompletedNormally(f);
@@ -581,7 +595,7 @@ public class RecursiveActionTest extends JSR166TestCase {
FailingFibAction f = new FailingFibAction(8);
assertSame(f, f.fork());
try {
- f.get(5L, TimeUnit.SECONDS);
+ f.get(5L, SECONDS);
shouldThrow();
} catch (ExecutionException success) {
Throwable cause = success.getCause();
diff --git a/jsr166-tests/src/test/java/jsr166/RecursiveTaskTest.java b/jsr166-tests/src/test/java/jsr166/RecursiveTaskTest.java
index 48b6470..7783370 100644
--- a/jsr166-tests/src/test/java/jsr166/RecursiveTaskTest.java
+++ b/jsr166-tests/src/test/java/jsr166/RecursiveTaskTest.java
@@ -6,20 +6,31 @@
package jsr166;
-import junit.framework.*;
+import static java.util.concurrent.TimeUnit.SECONDS;
+
+import java.util.HashSet;
import java.util.concurrent.CancellationException;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.ForkJoinTask;
-import java.util.concurrent.ForkJoinWorkerThread;
import java.util.concurrent.RecursiveTask;
-import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
-import static java.util.concurrent.TimeUnit.SECONDS;
-import java.util.HashSet;
+
+import junit.framework.Test;
+import junit.framework.TestSuite;
public class RecursiveTaskTest extends JSR166TestCase {
+ // android-note: Removed because the CTS runner does a bad job of
+ // retrying tests that have suite() declarations.
+ //
+ // public static void main(String[] args) {
+ // main(suite(), args);
+ // }
+ // public static Test suite() {
+ // return new TestSuite(...);
+ // }
+
private static ForkJoinPool mainPool() {
return new ForkJoinPool();
}
diff --git a/jsr166-tests/src/test/java/jsr166/ReentrantLockTest.java b/jsr166-tests/src/test/java/jsr166/ReentrantLockTest.java
index 6fe8122..17eaf76 100644
--- a/jsr166-tests/src/test/java/jsr166/ReentrantLockTest.java
+++ b/jsr166-tests/src/test/java/jsr166/ReentrantLockTest.java
@@ -8,34 +8,48 @@
package jsr166;
-import junit.framework.*;
-import java.util.concurrent.locks.Condition;
-import java.util.concurrent.locks.ReentrantLock;
+import static java.util.concurrent.TimeUnit.MILLISECONDS;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.HashSet;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.CyclicBarrier;
-import static java.util.concurrent.TimeUnit.MILLISECONDS;
-import java.util.*;
+import java.util.concurrent.locks.Condition;
+import java.util.concurrent.locks.ReentrantLock;
-public class ReentrantLockTest extends JSR166TestCase {
+import junit.framework.AssertionFailedError;
+import junit.framework.Test;
+import junit.framework.TestSuite;
+public class ReentrantLockTest extends JSR166TestCase {
+ // android-note: Removed because the CTS runner does a bad job of
+ // retrying tests that have suite() declarations.
+ //
+ // public static void main(String[] args) {
+ // main(suite(), args);
+ // }
+ // public static Test suite() {
+ // return new TestSuite(...);
+ // }
/**
- * A runnable calling lockInterruptibly
+ * A checked runnable calling lockInterruptibly
*/
class InterruptibleLockRunnable extends CheckedRunnable {
final ReentrantLock lock;
- InterruptibleLockRunnable(ReentrantLock l) { lock = l; }
+ InterruptibleLockRunnable(ReentrantLock lock) { this.lock = lock; }
public void realRun() throws InterruptedException {
lock.lockInterruptibly();
}
}
/**
- * A runnable calling lockInterruptibly that expects to be
+ * A checked runnable calling lockInterruptibly that expects to be
* interrupted
*/
class InterruptedLockRunnable extends CheckedInterruptedRunnable {
final ReentrantLock lock;
- InterruptedLockRunnable(ReentrantLock l) { lock = l; }
+ InterruptedLockRunnable(ReentrantLock lock) { this.lock = lock; }
public void realRun() throws InterruptedException {
lock.lockInterruptibly();
}
@@ -133,7 +147,7 @@ public class ReentrantLockTest extends JSR166TestCase {
lock.unlock();
}
- enum AwaitMethod { await, awaitTimed, awaitNanos, awaitUntil };
+ enum AwaitMethod { await, awaitTimed, awaitNanos, awaitUntil }
/**
* Awaits condition using the specified AwaitMethod.
@@ -156,6 +170,8 @@ public class ReentrantLockTest extends JSR166TestCase {
case awaitUntil:
assertTrue(c.awaitUntil(delayedDate(timeoutMillis)));
break;
+ default:
+ throw new AssertionError();
}
}
@@ -448,9 +464,7 @@ public class ReentrantLockTest extends JSR166TestCase {
barrier.await();
awaitTermination(t);
assertFalse(lock.isLocked());
- } catch (Exception e) {
- threadUnexpectedException(e);
- }
+ } catch (Exception fail) { threadUnexpectedException(fail); }
}
/**
@@ -462,9 +476,7 @@ public class ReentrantLockTest extends JSR166TestCase {
final PublicReentrantLock lock = new PublicReentrantLock(fair);
try {
lock.lockInterruptibly();
- } catch (InterruptedException ie) {
- threadUnexpectedException(ie);
- }
+ } catch (InterruptedException fail) { threadUnexpectedException(fail); }
assertLockedByMoi(lock);
Thread t = newStartedThread(new InterruptedLockRunnable(lock));
waitForQueuedThread(lock, t);
@@ -525,9 +537,7 @@ public class ReentrantLockTest extends JSR166TestCase {
assertTrue(nanosRemaining <= 0);
assertTrue(millisElapsedSince(startTime) >= timeoutMillis);
lock.unlock();
- } catch (InterruptedException e) {
- threadUnexpectedException(e);
- }
+ } catch (InterruptedException fail) { threadUnexpectedException(fail); }
}
/**
@@ -545,9 +555,7 @@ public class ReentrantLockTest extends JSR166TestCase {
assertFalse(c.await(timeoutMillis, MILLISECONDS));
assertTrue(millisElapsedSince(startTime) >= timeoutMillis);
lock.unlock();
- } catch (InterruptedException e) {
- threadUnexpectedException(e);
- }
+ } catch (InterruptedException fail) { threadUnexpectedException(fail); }
}
/**
@@ -566,9 +574,7 @@ public class ReentrantLockTest extends JSR166TestCase {
assertFalse(c.awaitUntil(new java.util.Date(d.getTime() + timeoutMillis)));
assertTrue(millisElapsedSince(startTime) >= timeoutMillis);
lock.unlock();
- } catch (InterruptedException e) {
- threadUnexpectedException(e);
- }
+ } catch (InterruptedException fail) { threadUnexpectedException(fail); }
}
/**
diff --git a/jsr166-tests/src/test/java/jsr166/ReentrantReadWriteLockTest.java b/jsr166-tests/src/test/java/jsr166/ReentrantReadWriteLockTest.java
index 2be27d2..7ef8ea3 100644
--- a/jsr166-tests/src/test/java/jsr166/ReentrantReadWriteLockTest.java
+++ b/jsr166-tests/src/test/java/jsr166/ReentrantReadWriteLockTest.java
@@ -8,16 +8,31 @@
package jsr166;
-import junit.framework.*;
+import static java.util.concurrent.TimeUnit.MILLISECONDS;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.concurrent.CountDownLatch;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
-import java.util.concurrent.CountDownLatch;
-import static java.util.concurrent.TimeUnit.MILLISECONDS;
-import java.util.*;
+
+import junit.framework.AssertionFailedError;
+import junit.framework.Test;
+import junit.framework.TestSuite;
public class ReentrantReadWriteLockTest extends JSR166TestCase {
+ // android-note: Removed because the CTS runner does a bad job of
+ // retrying tests that have suite() declarations.
+ //
+ // public static void main(String[] args) {
+ // main(suite(), args);
+ // }
+ // public static Test suite() {
+ // return new TestSuite(...);
+ // }
/**
* A runnable calling lockInterruptibly
@@ -142,7 +157,7 @@ public class ReentrantReadWriteLockTest extends JSR166TestCase {
lock.writeLock().unlock();
}
- enum AwaitMethod { await, awaitTimed, awaitNanos, awaitUntil };
+ enum AwaitMethod { await, awaitTimed, awaitNanos, awaitUntil }
/**
* Awaits condition using the specified AwaitMethod.
@@ -164,6 +179,8 @@ public class ReentrantReadWriteLockTest extends JSR166TestCase {
java.util.Date d = new java.util.Date();
assertTrue(c.awaitUntil(new java.util.Date(d.getTime() + 2 * LONG_DELAY_MS)));
break;
+ default:
+ throw new AssertionError();
}
}
@@ -818,9 +835,7 @@ public class ReentrantReadWriteLockTest extends JSR166TestCase {
new PublicReentrantReadWriteLock(fair);
try {
lock.writeLock().lockInterruptibly();
- } catch (InterruptedException ie) {
- threadUnexpectedException(ie);
- }
+ } catch (InterruptedException fail) { threadUnexpectedException(fail); }
Thread t = newStartedThread(new CheckedInterruptedRunnable() {
public void realRun() throws InterruptedException {
lock.writeLock().lockInterruptibly();
@@ -845,9 +860,7 @@ public class ReentrantReadWriteLockTest extends JSR166TestCase {
lock.readLock().lockInterruptibly();
lock.readLock().unlock();
lock.writeLock().lockInterruptibly();
- } catch (InterruptedException ie) {
- threadUnexpectedException(ie);
- }
+ } catch (InterruptedException fail) { threadUnexpectedException(fail); }
Thread t = newStartedThread(new CheckedInterruptedRunnable() {
public void realRun() throws InterruptedException {
lock.readLock().lockInterruptibly();
@@ -873,7 +886,9 @@ public class ReentrantReadWriteLockTest extends JSR166TestCase {
await(c, awaitMethod);
shouldThrow();
} catch (IllegalMonitorStateException success) {
- } catch (InterruptedException e) { threadUnexpectedException(e); }
+ } catch (InterruptedException fail) {
+ threadUnexpectedException(fail);
+ }
assertTrue(millisElapsedSince(startTime) < LONG_DELAY_MS);
}
}
@@ -924,9 +939,7 @@ public class ReentrantReadWriteLockTest extends JSR166TestCase {
assertTrue(nanosRemaining <= 0);
assertTrue(millisElapsedSince(startTime) >= timeoutMillis);
lock.writeLock().unlock();
- } catch (InterruptedException e) {
- threadUnexpectedException(e);
- }
+ } catch (InterruptedException fail) { threadUnexpectedException(fail); }
}
/**
@@ -945,9 +958,7 @@ public class ReentrantReadWriteLockTest extends JSR166TestCase {
assertFalse(c.await(timeoutMillis, MILLISECONDS));
assertTrue(millisElapsedSince(startTime) >= timeoutMillis);
lock.writeLock().unlock();
- } catch (InterruptedException e) {
- threadUnexpectedException(e);
- }
+ } catch (InterruptedException fail) { threadUnexpectedException(fail); }
}
/**
@@ -967,9 +978,7 @@ public class ReentrantReadWriteLockTest extends JSR166TestCase {
assertFalse(c.awaitUntil(new java.util.Date(d.getTime() + timeoutMillis)));
assertTrue(millisElapsedSince(startTime) >= timeoutMillis);
lock.writeLock().unlock();
- } catch (InterruptedException e) {
- threadUnexpectedException(e);
- }
+ } catch (InterruptedException fail) { threadUnexpectedException(fail); }
}
/**
diff --git a/jsr166-tests/src/test/java/jsr166/ScheduledExecutorSubclassTest.java b/jsr166-tests/src/test/java/jsr166/ScheduledExecutorSubclassTest.java
index b72ad02..a93feea 100644
--- a/jsr166-tests/src/test/java/jsr166/ScheduledExecutorSubclassTest.java
+++ b/jsr166-tests/src/test/java/jsr166/ScheduledExecutorSubclassTest.java
@@ -6,13 +6,42 @@
package jsr166;
-import junit.framework.*;
-import java.util.*;
-import java.util.concurrent.*;
import static java.util.concurrent.TimeUnit.MILLISECONDS;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.Callable;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.Delayed;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Future;
+import java.util.concurrent.RejectedExecutionException;
+import java.util.concurrent.RejectedExecutionHandler;
+import java.util.concurrent.RunnableScheduledFuture;
+import java.util.concurrent.ScheduledFuture;
+import java.util.concurrent.ScheduledThreadPoolExecutor;
+import java.util.concurrent.ThreadFactory;
+import java.util.concurrent.ThreadPoolExecutor;
+import java.util.concurrent.TimeoutException;
+import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
public class ScheduledExecutorSubclassTest extends JSR166TestCase {
+ // android-note: Removed because the CTS runner does a bad job of
+ // retrying tests that have suite() declarations.
+ //
+ // public static void main(String[] args) {
+ // main(suite(), args);
+ // }
+ // public static Test suite() {
+ // return new TestSuite(...);
+ // }
static class CustomTask<V> implements RunnableScheduledFuture<V> {
RunnableScheduledFuture<V> task;
@@ -189,17 +218,27 @@ public class ScheduledExecutorSubclassTest extends JSR166TestCase {
*/
public void testFixedRateSequence() throws InterruptedException {
CustomExecutor p = new CustomExecutor(1);
- RunnableCounter counter = new RunnableCounter();
- ScheduledFuture h =
- p.scheduleAtFixedRate(counter, 0, 1, MILLISECONDS);
- delay(SMALL_DELAY_MS);
- h.cancel(true);
- int c = counter.count.get();
- // By time scaling conventions, we must have at least
- // an execution per SHORT delay, but no more than one SHORT more
- assertTrue(c >= SMALL_DELAY_MS / SHORT_DELAY_MS);
- assertTrue(c <= SMALL_DELAY_MS + SHORT_DELAY_MS);
- joinPool(p);
+ try {
+ for (int delay = 1; delay <= LONG_DELAY_MS; delay *= 3) {
+ long startTime = System.nanoTime();
+ int cycles = 10;
+ final CountDownLatch done = new CountDownLatch(cycles);
+ Runnable task = new CheckedRunnable() {
+ public void realRun() { done.countDown(); }};
+ ScheduledFuture h =
+ p.scheduleAtFixedRate(task, 0, delay, MILLISECONDS);
+ done.await();
+ h.cancel(true);
+ double normalizedTime =
+ (double) millisElapsedSince(startTime) / delay;
+ if (normalizedTime >= cycles - 1 &&
+ normalizedTime <= cycles)
+ return;
+ }
+ throw new AssertionError("unexpected execution rate");
+ } finally {
+ joinPool(p);
+ }
}
/**
@@ -207,15 +246,27 @@ public class ScheduledExecutorSubclassTest extends JSR166TestCase {
*/
public void testFixedDelaySequence() throws InterruptedException {
CustomExecutor p = new CustomExecutor(1);
- RunnableCounter counter = new RunnableCounter();
- ScheduledFuture h =
- p.scheduleWithFixedDelay(counter, 0, 1, MILLISECONDS);
- delay(SMALL_DELAY_MS);
- h.cancel(true);
- int c = counter.count.get();
- assertTrue(c >= SMALL_DELAY_MS / SHORT_DELAY_MS);
- assertTrue(c <= SMALL_DELAY_MS + SHORT_DELAY_MS);
- joinPool(p);
+ try {
+ for (int delay = 1; delay <= LONG_DELAY_MS; delay *= 3) {
+ long startTime = System.nanoTime();
+ int cycles = 10;
+ final CountDownLatch done = new CountDownLatch(cycles);
+ Runnable task = new CheckedRunnable() {
+ public void realRun() { done.countDown(); }};
+ ScheduledFuture h =
+ p.scheduleWithFixedDelay(task, 0, delay, MILLISECONDS);
+ done.await();
+ h.cancel(true);
+ double normalizedTime =
+ (double) millisElapsedSince(startTime) / delay;
+ if (normalizedTime >= cycles - 1 &&
+ normalizedTime <= cycles)
+ return;
+ }
+ throw new AssertionError("unexpected execution rate");
+ } finally {
+ joinPool(p);
+ }
}
/**
diff --git a/jsr166-tests/src/test/java/jsr166/ScheduledExecutorTest.java b/jsr166-tests/src/test/java/jsr166/ScheduledExecutorTest.java
index 4eea2c9..a2e83d0 100644
--- a/jsr166-tests/src/test/java/jsr166/ScheduledExecutorTest.java
+++ b/jsr166-tests/src/test/java/jsr166/ScheduledExecutorTest.java
@@ -8,13 +8,37 @@
package jsr166;
-import junit.framework.*;
-import java.util.*;
-import java.util.concurrent.*;
import static java.util.concurrent.TimeUnit.MILLISECONDS;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.Callable;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Future;
+import java.util.concurrent.RejectedExecutionException;
+import java.util.concurrent.ScheduledFuture;
+import java.util.concurrent.ScheduledThreadPoolExecutor;
+import java.util.concurrent.ThreadFactory;
+import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.atomic.AtomicInteger;
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
public class ScheduledExecutorTest extends JSR166TestCase {
+ // android-note: Removed because the CTS runner does a bad job of
+ // retrying tests that have suite() declarations.
+ //
+ // public static void main(String[] args) {
+ // main(suite(), args);
+ // }
+ // public static Test suite() {
+ // return new TestSuite(...);
+ // }
/**
* execute successfully executes a runnable
@@ -137,17 +161,27 @@ public class ScheduledExecutorTest extends JSR166TestCase {
*/
public void testFixedRateSequence() throws InterruptedException {
ScheduledThreadPoolExecutor p = new ScheduledThreadPoolExecutor(1);
- RunnableCounter counter = new RunnableCounter();
- ScheduledFuture h =
- p.scheduleAtFixedRate(counter, 0, 1, MILLISECONDS);
- delay(SMALL_DELAY_MS);
- h.cancel(true);
- int c = counter.count.get();
- // By time scaling conventions, we must have at least
- // an execution per SHORT delay, but no more than one SHORT more
- assertTrue(c >= SMALL_DELAY_MS / SHORT_DELAY_MS);
- assertTrue(c <= SMALL_DELAY_MS + SHORT_DELAY_MS);
- joinPool(p);
+ try {
+ for (int delay = 1; delay <= LONG_DELAY_MS; delay *= 3) {
+ long startTime = System.nanoTime();
+ int cycles = 10;
+ final CountDownLatch done = new CountDownLatch(cycles);
+ Runnable task = new CheckedRunnable() {
+ public void realRun() { done.countDown(); }};
+ ScheduledFuture h =
+ p.scheduleAtFixedRate(task, 0, delay, MILLISECONDS);
+ done.await();
+ h.cancel(true);
+ double normalizedTime =
+ (double) millisElapsedSince(startTime) / delay;
+ if (normalizedTime >= cycles - 1 &&
+ normalizedTime <= cycles)
+ return;
+ }
+ throw new AssertionError("unexpected execution rate");
+ } finally {
+ joinPool(p);
+ }
}
/**
@@ -155,15 +189,27 @@ public class ScheduledExecutorTest extends JSR166TestCase {
*/
public void testFixedDelaySequence() throws InterruptedException {
ScheduledThreadPoolExecutor p = new ScheduledThreadPoolExecutor(1);
- RunnableCounter counter = new RunnableCounter();
- ScheduledFuture h =
- p.scheduleWithFixedDelay(counter, 0, 1, MILLISECONDS);
- delay(SMALL_DELAY_MS);
- h.cancel(true);
- int c = counter.count.get();
- assertTrue(c >= SMALL_DELAY_MS / SHORT_DELAY_MS);
- assertTrue(c <= SMALL_DELAY_MS + SHORT_DELAY_MS);
- joinPool(p);
+ try {
+ for (int delay = 1; delay <= LONG_DELAY_MS; delay *= 3) {
+ long startTime = System.nanoTime();
+ int cycles = 10;
+ final CountDownLatch done = new CountDownLatch(cycles);
+ Runnable task = new CheckedRunnable() {
+ public void realRun() { done.countDown(); }};
+ ScheduledFuture h =
+ p.scheduleWithFixedDelay(task, 0, delay, MILLISECONDS);
+ done.await();
+ h.cancel(true);
+ double normalizedTime =
+ (double) millisElapsedSince(startTime) / delay;
+ if (normalizedTime >= cycles - 1 &&
+ normalizedTime <= cycles)
+ return;
+ }
+ throw new AssertionError("unexpected execution rate");
+ } finally {
+ joinPool(p);
+ }
}
/**
diff --git a/jsr166-tests/src/test/java/jsr166/SemaphoreTest.java b/jsr166-tests/src/test/java/jsr166/SemaphoreTest.java
index f303285..db4f4b4 100644
--- a/jsr166-tests/src/test/java/jsr166/SemaphoreTest.java
+++ b/jsr166-tests/src/test/java/jsr166/SemaphoreTest.java
@@ -8,14 +8,26 @@
package jsr166;
-import junit.framework.*;
-import java.util.*;
+import static java.util.concurrent.TimeUnit.MILLISECONDS;
+
+import java.util.Collection;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Semaphore;
-import static java.util.concurrent.TimeUnit.MILLISECONDS;
-public class SemaphoreTest extends JSR166TestCase {
+import junit.framework.AssertionFailedError;
+import junit.framework.Test;
+import junit.framework.TestSuite;
+public class SemaphoreTest extends JSR166TestCase {
+ // android-note: Removed because the CTS runner does a bad job of
+ // retrying tests that have suite() declarations.
+ //
+ // public static void main(String[] args) {
+ // main(suite(), args);
+ // }
+ // public static Test suite() {
+ // return new TestSuite(...);
+ // }
/**
* Subclass to expose protected methods
*/
@@ -608,7 +620,7 @@ public class SemaphoreTest extends JSR166TestCase {
assertTrue(t2.isAlive());
s.release();
awaitTermination(t2);
- }
+ }
/**
* toString indicates current number of permits
diff --git a/jsr166-tests/src/test/java/jsr166/SynchronousQueueTest.java b/jsr166-tests/src/test/java/jsr166/SynchronousQueueTest.java
index bd030cf..605a955 100644
--- a/jsr166-tests/src/test/java/jsr166/SynchronousQueueTest.java
+++ b/jsr166-tests/src/test/java/jsr166/SynchronousQueueTest.java
@@ -8,22 +8,48 @@
package jsr166;
-import junit.framework.*;
-import java.util.Arrays;
+import static java.util.concurrent.TimeUnit.MILLISECONDS;
+
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Collection;
import java.util.Iterator;
import java.util.NoSuchElementException;
-import java.util.Queue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Executors;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.SynchronousQueue;
-import static java.util.concurrent.TimeUnit.MILLISECONDS;
+
+import junit.framework.Test;
public class SynchronousQueueTest extends JSR166TestCase {
+ // android-note: These tests have been moved into their own separate
+ // classes to work around CTS issues.
+ //
+ // public static class Fair extends BlockingQueueTest {
+ // protected BlockingQueue emptyCollection() {
+ // return new SynchronousQueue(true);
+ // }
+ // }
+ //
+ // public static class NonFair extends BlockingQueueTest {
+ // protected BlockingQueue emptyCollection() {
+ // return new SynchronousQueue(false);
+ // }
+ // }
+ //
+ // public static void main(String[] args) {
+ // main(suite(), args);
+ // }
+ //
+ // public static Test suite() {
+ // return newTestSuite(SynchronousQueueTest.class,
+ // new Fair().testSuite(),
+ // new NonFair().testSuite());
+ // }
+
/**
* Any SynchronousQueue is both empty and full
*/
@@ -402,7 +428,7 @@ public class SynchronousQueueTest extends JSR166TestCase {
public void testToArray_null(boolean fair) {
final SynchronousQueue q = new SynchronousQueue(fair);
try {
- Object o[] = q.toArray(null);
+ Object[] o = q.toArray(null);
shouldThrow();
} catch (NullPointerException success) {}
}
@@ -413,13 +439,7 @@ public class SynchronousQueueTest extends JSR166TestCase {
public void testIterator() { testIterator(false); }
public void testIterator_fair() { testIterator(true); }
public void testIterator(boolean fair) {
- final SynchronousQueue q = new SynchronousQueue(fair);
- Iterator it = q.iterator();
- assertFalse(it.hasNext());
- try {
- Object x = it.next();
- shouldThrow();
- } catch (NoSuchElementException success) {}
+ assertIteratorExhausted(new SynchronousQueue(fair).iterator());
}
/**
@@ -586,4 +606,13 @@ public class SynchronousQueueTest extends JSR166TestCase {
awaitTermination(t2);
}
+ /**
+ * remove(null), contains(null) always return false
+ */
+ public void testNeverContainsNull() {
+ Collection<?> q = new SynchronousQueue();
+ assertFalse(q.contains(null));
+ assertFalse(q.remove(null));
+ }
+
}
diff --git a/jsr166-tests/src/test/java/jsr166/SystemTest.java b/jsr166-tests/src/test/java/jsr166/SystemTest.java
index 32caec2..6918374 100644
--- a/jsr166-tests/src/test/java/jsr166/SystemTest.java
+++ b/jsr166-tests/src/test/java/jsr166/SystemTest.java
@@ -8,9 +8,19 @@
package jsr166;
-import junit.framework.*;
+import junit.framework.Test;
+import junit.framework.TestSuite;
public class SystemTest extends JSR166TestCase {
+ // android-note: Removed because the CTS runner does a bad job of
+ // retrying tests that have suite() declarations.
+ //
+ // public static void main(String[] args) {
+ // main(suite(), args);
+ // }
+ // public static Test suite() {
+ // return new TestSuite(...);
+ // }
/**
* Worst case rounding for millisecs; set for 60 cycle millis clock.
diff --git a/jsr166-tests/src/test/java/jsr166/ThreadLocalRandomTest.java b/jsr166-tests/src/test/java/jsr166/ThreadLocalRandomTest.java
index 665a2b7..4ae141d 100644
--- a/jsr166-tests/src/test/java/jsr166/ThreadLocalRandomTest.java
+++ b/jsr166-tests/src/test/java/jsr166/ThreadLocalRandomTest.java
@@ -6,14 +6,25 @@
package jsr166;
-import junit.framework.*;
-import java.util.*;
import java.util.concurrent.ThreadLocalRandom;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.atomic.AtomicReference;
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
public class ThreadLocalRandomTest extends JSR166TestCase {
+ // android-note: Removed because the CTS runner does a bad job of
+ // retrying tests that have suite() declarations.
+ //
+ // public static void main(String[] args) {
+ // main(suite(), args);
+ // }
+ // public static Test suite() {
+ // return new TestSuite(...);
+ // }
+
/*
* Testing coverage notes:
*
@@ -23,15 +34,18 @@ public class ThreadLocalRandomTest extends JSR166TestCase {
* across multiples of primes.
*/
- //
+ // max numbers of calls to detect getting stuck on one value
static final int NCALLS = 10000;
// max sampled int bound
static final int MAX_INT_BOUND = (1 << 28);
- // Max sampled long bound
+ // max sampled long bound
static final long MAX_LONG_BOUND = (1L << 42);
+ // Number of replications for other checks
+ static final int REPS = 20;
+
/**
* setSeed throws UnsupportedOperationException
*/
@@ -43,7 +57,7 @@ public class ThreadLocalRandomTest extends JSR166TestCase {
}
/**
- * Repeated calls to nextInt produce at least one different result
+ * Repeated calls to nextInt produce at least two distinct results
*/
public void testNextInt() {
int f = ThreadLocalRandom.current().nextInt();
@@ -54,7 +68,7 @@ public class ThreadLocalRandomTest extends JSR166TestCase {
}
/**
- * Repeated calls to nextLong produce at least one different result
+ * Repeated calls to nextLong produce at least two distinct results
*/
public void testNextLong() {
long f = ThreadLocalRandom.current().nextLong();
@@ -65,7 +79,7 @@ public class ThreadLocalRandomTest extends JSR166TestCase {
}
/**
- * Repeated calls to nextBoolean produce at least one different result
+ * Repeated calls to nextBoolean produce at least two distinct results
*/
public void testNextBoolean() {
boolean f = ThreadLocalRandom.current().nextBoolean();
@@ -76,7 +90,7 @@ public class ThreadLocalRandomTest extends JSR166TestCase {
}
/**
- * Repeated calls to nextFloat produce at least one different result
+ * Repeated calls to nextFloat produce at least two distinct results
*/
public void testNextFloat() {
float f = ThreadLocalRandom.current().nextFloat();
@@ -87,18 +101,18 @@ public class ThreadLocalRandomTest extends JSR166TestCase {
}
/**
- * Repeated calls to nextDouble produce at least one different result
+ * Repeated calls to nextDouble produce at least two distinct results
*/
public void testNextDouble() {
double f = ThreadLocalRandom.current().nextDouble();
- double i = 0;
+ int i = 0;
while (i < NCALLS && ThreadLocalRandom.current().nextDouble() == f)
++i;
assertTrue(i < NCALLS);
}
/**
- * Repeated calls to nextGaussian produce at least one different result
+ * Repeated calls to nextGaussian produce at least two distinct results
*/
public void testNextGaussian() {
double f = ThreadLocalRandom.current().nextGaussian();
@@ -109,28 +123,39 @@ public class ThreadLocalRandomTest extends JSR166TestCase {
}
/**
- * nextInt(negative) throws IllegalArgumentException;
+ * nextInt(non-positive) throws IllegalArgumentException
*/
- public void testNextIntBoundedNeg() {
- try {
- int f = ThreadLocalRandom.current().nextInt(-17);
- shouldThrow();
- } catch (IllegalArgumentException success) {}
+ public void testNextIntBoundNonPositive() {
+ ThreadLocalRandom rnd = ThreadLocalRandom.current();
+ for (int bound : new int[] { 0, -17, Integer.MIN_VALUE }) {
+ try {
+ rnd.nextInt(bound);
+ shouldThrow();
+ } catch (IllegalArgumentException success) {}
+ }
}
/**
- * nextInt(least >= bound) throws IllegalArgumentException;
+ * nextInt(least >= bound) throws IllegalArgumentException
*/
public void testNextIntBadBounds() {
- try {
- int f = ThreadLocalRandom.current().nextInt(17, 2);
- shouldThrow();
- } catch (IllegalArgumentException success) {}
+ int[][] badBoundss = {
+ { 17, 2 },
+ { -42, -42 },
+ { Integer.MAX_VALUE, Integer.MIN_VALUE },
+ };
+ ThreadLocalRandom rnd = ThreadLocalRandom.current();
+ for (int[] badBounds : badBoundss) {
+ try {
+ rnd.nextInt(badBounds[0], badBounds[1]);
+ shouldThrow();
+ } catch (IllegalArgumentException success) {}
+ }
}
/**
* nextInt(bound) returns 0 <= value < bound;
- * repeated calls produce at least one different result
+ * repeated calls produce at least two distinct results
*/
public void testNextIntBounded() {
// sample bound space across prime number increments
@@ -150,7 +175,7 @@ public class ThreadLocalRandomTest extends JSR166TestCase {
/**
* nextInt(least, bound) returns least <= value < bound;
- * repeated calls produce at least one different result
+ * repeated calls produce at least two distinct results
*/
public void testNextIntBounded2() {
for (int least = -15485863; least < MAX_INT_BOUND; least += 524959) {
@@ -170,28 +195,39 @@ public class ThreadLocalRandomTest extends JSR166TestCase {
}
/**
- * nextLong(negative) throws IllegalArgumentException;
+ * nextLong(non-positive) throws IllegalArgumentException
*/
- public void testNextLongBoundedNeg() {
- try {
- long f = ThreadLocalRandom.current().nextLong(-17);
- shouldThrow();
- } catch (IllegalArgumentException success) {}
+ public void testNextLongBoundNonPositive() {
+ ThreadLocalRandom rnd = ThreadLocalRandom.current();
+ for (long bound : new long[] { 0L, -17L, Long.MIN_VALUE }) {
+ try {
+ rnd.nextLong(bound);
+ shouldThrow();
+ } catch (IllegalArgumentException success) {}
+ }
}
/**
- * nextLong(least >= bound) throws IllegalArgumentException;
+ * nextLong(least >= bound) throws IllegalArgumentException
*/
public void testNextLongBadBounds() {
- try {
- long f = ThreadLocalRandom.current().nextLong(17, 2);
- shouldThrow();
- } catch (IllegalArgumentException success) {}
+ long[][] badBoundss = {
+ { 17L, 2L },
+ { -42L, -42L },
+ { Long.MAX_VALUE, Long.MIN_VALUE },
+ };
+ ThreadLocalRandom rnd = ThreadLocalRandom.current();
+ for (long[] badBounds : badBoundss) {
+ try {
+ rnd.nextLong(badBounds[0], badBounds[1]);
+ shouldThrow();
+ } catch (IllegalArgumentException success) {}
+ }
}
/**
* nextLong(bound) returns 0 <= value < bound;
- * repeated calls produce at least one different result
+ * repeated calls produce at least two distinct results
*/
public void testNextLongBounded() {
for (long bound = 2; bound < MAX_LONG_BOUND; bound += 15485863) {
@@ -210,7 +246,7 @@ public class ThreadLocalRandomTest extends JSR166TestCase {
/**
* nextLong(least, bound) returns least <= value < bound;
- * repeated calls produce at least one different result
+ * repeated calls produce at least two distinct results
*/
public void testNextLongBounded2() {
for (long least = -86028121; least < MAX_LONG_BOUND; least += 982451653L) {
@@ -230,8 +266,28 @@ public class ThreadLocalRandomTest extends JSR166TestCase {
}
/**
+ * nextDouble(non-positive) throws IllegalArgumentException
+ */
+ public void testNextDoubleBoundNonPositive() {
+ ThreadLocalRandom rnd = ThreadLocalRandom.current();
+ double[] badBounds = {
+ 0.0d,
+ -17.0d,
+ -Double.MIN_VALUE,
+ Double.NEGATIVE_INFINITY,
+ Double.NaN,
+ };
+ for (double bound : badBounds) {
+ try {
+ rnd.nextDouble(bound);
+ shouldThrow();
+ } catch (IllegalArgumentException success) {}
+ }
+ }
+
+ /**
* nextDouble(least, bound) returns least <= value < bound;
- * repeated calls produce at least one different result
+ * repeated calls produce at least two distinct results
*/
public void testNextDoubleBounded2() {
for (double least = 0.0001; least < 1.0e20; least *= 8) {
@@ -263,7 +319,7 @@ public class ThreadLocalRandomTest extends JSR166TestCase {
long firstRand = 0;
ThreadLocalRandom firstThreadLocalRandom = null;
- final CheckedRunnable getRandomState = new CheckedRunnable() {
+ Runnable getRandomState = new CheckedRunnable() {
public void realRun() {
ThreadLocalRandom current = ThreadLocalRandom.current();
assertSame(current, ThreadLocalRandom.current());
diff --git a/jsr166-tests/src/test/java/jsr166/ThreadLocalTest.java b/jsr166-tests/src/test/java/jsr166/ThreadLocalTest.java
index 885c2b2..7f5f072 100644
--- a/jsr166-tests/src/test/java/jsr166/ThreadLocalTest.java
+++ b/jsr166-tests/src/test/java/jsr166/ThreadLocalTest.java
@@ -8,10 +8,19 @@
package jsr166;
-import junit.framework.*;
-import java.util.concurrent.Semaphore;
+import junit.framework.Test;
+import junit.framework.TestSuite;
public class ThreadLocalTest extends JSR166TestCase {
+ // android-note: Removed because the CTS runner does a bad job of
+ // retrying tests that have suite() declarations.
+ //
+ // public static void main(String[] args) {
+ // main(suite(), args);
+ // }
+ // public static Test suite() {
+ // return new TestSuite(...);
+ // }
static ThreadLocal<Integer> tl = new ThreadLocal<Integer>() {
public Integer initialValue() {
@@ -85,7 +94,7 @@ public class ThreadLocalTest extends JSR166TestCase {
*/
public void testGenericITL() throws InterruptedException {
final int threadCount = 10;
- final int x[] = new int[threadCount];
+ final int[] x = new int[threadCount];
Thread progenitor = new ITLThread(x);
progenitor.start();
progenitor.join();
diff --git a/jsr166-tests/src/test/java/jsr166/ThreadPoolExecutorSubclassTest.java b/jsr166-tests/src/test/java/jsr166/ThreadPoolExecutorSubclassTest.java
index f16f422..5f38d39 100644
--- a/jsr166-tests/src/test/java/jsr166/ThreadPoolExecutorSubclassTest.java
+++ b/jsr166-tests/src/test/java/jsr166/ThreadPoolExecutorSubclassTest.java
@@ -8,14 +8,44 @@
package jsr166;
-import junit.framework.*;
-import java.util.concurrent.*;
import static java.util.concurrent.TimeUnit.MILLISECONDS;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.ArrayBlockingQueue;
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.Callable;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Future;
+import java.util.concurrent.FutureTask;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.RejectedExecutionException;
+import java.util.concurrent.RejectedExecutionHandler;
+import java.util.concurrent.RunnableFuture;
+import java.util.concurrent.SynchronousQueue;
+import java.util.concurrent.ThreadFactory;
+import java.util.concurrent.ThreadPoolExecutor;
+import java.util.concurrent.TimeoutException;
+import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;
-import java.util.*;
+
+import junit.framework.Test;
+import junit.framework.TestSuite;
public class ThreadPoolExecutorSubclassTest extends JSR166TestCase {
+ // android-note: Removed because the CTS runner does a bad job of
+ // retrying tests that have suite() declarations.
+ //
+ // public static void main(String[] args) {
+ // main(suite(), args);
+ // }
+ // public static Test suite() {
+ // return new TestSuite(...);
+ // }
static class CustomTask<V> implements RunnableFuture<V> {
final Callable<V> callable;
@@ -33,7 +63,7 @@ public class ThreadPoolExecutorSubclassTest extends JSR166TestCase {
CustomTask(final Runnable r, final V res) {
if (r == null) throw new NullPointerException();
callable = new Callable<V>() {
- public V call() throws Exception { r.run(); return res; }};
+ public V call() throws Exception { r.run(); return res; }};
}
public boolean isDone() {
lock.lock(); try { return done; } finally { lock.unlock() ; }
@@ -1244,11 +1274,10 @@ public class ThreadPoolExecutorSubclassTest extends JSR166TestCase {
CustomTPE p = new CustomTPE();
try {
final CountDownLatch done = new CountDownLatch(1);
- final CheckedRunnable task = new CheckedRunnable() {
+ p.execute(new CheckedRunnable() {
public void realRun() {
done.countDown();
- }};
- p.execute(task);
+ }});
await(p.afterCalled);
assertEquals(0, done.getCount());
assertTrue(p.afterCalled());
diff --git a/jsr166-tests/src/test/java/jsr166/ThreadPoolExecutorTest.java b/jsr166-tests/src/test/java/jsr166/ThreadPoolExecutorTest.java
index 55f769b..52a7002 100644
--- a/jsr166-tests/src/test/java/jsr166/ThreadPoolExecutorTest.java
+++ b/jsr166-tests/src/test/java/jsr166/ThreadPoolExecutorTest.java
@@ -8,13 +8,41 @@
package jsr166;
-import junit.framework.*;
-import java.util.concurrent.*;
import static java.util.concurrent.TimeUnit.MILLISECONDS;
import static java.util.concurrent.TimeUnit.NANOSECONDS;
-import java.util.*;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.ArrayBlockingQueue;
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.Callable;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Future;
+import java.util.concurrent.FutureTask;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.RejectedExecutionException;
+import java.util.concurrent.RejectedExecutionHandler;
+import java.util.concurrent.SynchronousQueue;
+import java.util.concurrent.ThreadFactory;
+import java.util.concurrent.ThreadPoolExecutor;
+import java.util.concurrent.TimeUnit;
+
+import junit.framework.Test;
+import junit.framework.TestSuite;
public class ThreadPoolExecutorTest extends JSR166TestCase {
+ // android-note: Removed because the CTS runner does a bad job of
+ // retrying tests that have suite() declarations.
+ //
+ // public static void main(String[] args) {
+ // main(suite(), args);
+ // }
+ // public static Test suite() {
+ // return new TestSuite(...);
+ // }
static class ExtendedTPE extends ThreadPoolExecutor {
final CountDownLatch beforeCalled = new CountDownLatch(1);
@@ -1371,11 +1399,10 @@ public class ThreadPoolExecutorTest extends JSR166TestCase {
ExtendedTPE p = new ExtendedTPE();
try {
final CountDownLatch done = new CountDownLatch(1);
- final CheckedRunnable task = new CheckedRunnable() {
+ p.execute(new CheckedRunnable() {
public void realRun() {
done.countDown();
- }};
- p.execute(task);
+ }});
await(p.afterCalled);
assertEquals(0, done.getCount());
assertTrue(p.afterCalled());
diff --git a/jsr166-tests/src/test/java/jsr166/ThreadTest.java b/jsr166-tests/src/test/java/jsr166/ThreadTest.java
index 12c2f8a..27f22ca 100644
--- a/jsr166-tests/src/test/java/jsr166/ThreadTest.java
+++ b/jsr166-tests/src/test/java/jsr166/ThreadTest.java
@@ -8,9 +8,19 @@
package jsr166;
-import junit.framework.*;
+import junit.framework.Test;
+import junit.framework.TestSuite;
public class ThreadTest extends JSR166TestCase {
+ // android-note: Removed because the CTS runner does a bad job of
+ // retrying tests that have suite() declarations.
+ //
+ // public static void main(String[] args) {
+ // main(suite(), args);
+ // }
+ // public static Test suite() {
+ // return new TestSuite(...);
+ // }
static class MyHandler implements Thread.UncaughtExceptionHandler {
public void uncaughtException(Thread t, Throwable e) {
@@ -28,11 +38,14 @@ public class ThreadTest extends JSR166TestCase {
Thread current = Thread.currentThread();
ThreadGroup tg = current.getThreadGroup();
MyHandler eh = new MyHandler();
- assertEquals(tg, current.getUncaughtExceptionHandler());
+ assertSame(tg, current.getUncaughtExceptionHandler());
current.setUncaughtExceptionHandler(eh);
- assertEquals(eh, current.getUncaughtExceptionHandler());
- current.setUncaughtExceptionHandler(null);
- assertEquals(tg, current.getUncaughtExceptionHandler());
+ try {
+ assertSame(eh, current.getUncaughtExceptionHandler());
+ } finally {
+ current.setUncaughtExceptionHandler(null);
+ }
+ assertSame(tg, current.getUncaughtExceptionHandler());
}
/**
@@ -40,24 +53,27 @@ public class ThreadTest extends JSR166TestCase {
* setDefaultUncaughtExceptionHandler.
*/
public void testGetAndSetDefaultUncaughtExceptionHandler() {
- // BEGIN android-remove (when running as cts the RuntimeInit will
- // set a default handler)
+ // android-note: Removed assertion; all "normal" android apps (including CTS tests) have a
+ // default uncaught exception handler installed by the framework.
+ //
// assertEquals(null, Thread.getDefaultUncaughtExceptionHandler());
- // END android-remove
// failure due to securityException is OK.
// Would be nice to explicitly test both ways, but cannot yet.
+ Thread.UncaughtExceptionHandler defaultHandler
+ = Thread.getDefaultUncaughtExceptionHandler();
+ MyHandler eh = new MyHandler();
try {
- Thread current = Thread.currentThread();
- ThreadGroup tg = current.getThreadGroup();
- MyHandler eh = new MyHandler();
Thread.setDefaultUncaughtExceptionHandler(eh);
- assertEquals(eh, Thread.getDefaultUncaughtExceptionHandler());
- Thread.setDefaultUncaughtExceptionHandler(null);
- }
- catch (SecurityException ok) {
+ try {
+ assertSame(eh, Thread.getDefaultUncaughtExceptionHandler());
+ } finally {
+ Thread.setDefaultUncaughtExceptionHandler(defaultHandler);
+ }
+ } catch (SecurityException ok) {
+ assertNotNull(System.getSecurityManager());
}
- assertEquals(null, Thread.getDefaultUncaughtExceptionHandler());
+ assertSame(defaultHandler, Thread.getDefaultUncaughtExceptionHandler());
}
// How to test actually using UEH within junit?
diff --git a/jsr166-tests/src/test/java/jsr166/TimeUnitTest.java b/jsr166-tests/src/test/java/jsr166/TimeUnitTest.java
index 7fa9e1a..2c9529b 100644
--- a/jsr166-tests/src/test/java/jsr166/TimeUnitTest.java
+++ b/jsr166-tests/src/test/java/jsr166/TimeUnitTest.java
@@ -8,11 +8,30 @@
package jsr166;
-import junit.framework.*;
+import static java.util.concurrent.TimeUnit.DAYS;
+import static java.util.concurrent.TimeUnit.HOURS;
+import static java.util.concurrent.TimeUnit.MICROSECONDS;
+import static java.util.concurrent.TimeUnit.MILLISECONDS;
+import static java.util.concurrent.TimeUnit.MINUTES;
+import static java.util.concurrent.TimeUnit.NANOSECONDS;
+import static java.util.concurrent.TimeUnit.SECONDS;
+
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
public class TimeUnitTest extends JSR166TestCase {
+ // android-note: Removed because the CTS runner does a bad job of
+ // retrying tests that have suite() declarations.
+ //
+ // public static void main(String[] args) {
+ // main(suite(), args);
+ // }
+ // public static Test suite() {
+ // return new TestSuite(...);
+ // }
// (loops to 88888 check increments at all time divisions.)
@@ -22,92 +41,64 @@ public class TimeUnitTest extends JSR166TestCase {
public void testConvert() {
for (long t = 0; t < 88888; ++t) {
assertEquals(t*60*60*24,
- TimeUnit.SECONDS.convert(t,
- TimeUnit.DAYS));
+ SECONDS.convert(t, DAYS));
assertEquals(t*60*60,
- TimeUnit.SECONDS.convert(t,
- TimeUnit.HOURS));
+ SECONDS.convert(t, HOURS));
assertEquals(t*60,
- TimeUnit.SECONDS.convert(t,
- TimeUnit.MINUTES));
+ SECONDS.convert(t, MINUTES));
assertEquals(t,
- TimeUnit.SECONDS.convert(t,
- TimeUnit.SECONDS));
+ SECONDS.convert(t, SECONDS));
assertEquals(t,
- TimeUnit.SECONDS.convert(1000L*t,
- TimeUnit.MILLISECONDS));
+ SECONDS.convert(1000L*t, MILLISECONDS));
assertEquals(t,
- TimeUnit.SECONDS.convert(1000000L*t,
- TimeUnit.MICROSECONDS));
+ SECONDS.convert(1000000L*t, MICROSECONDS));
assertEquals(t,
- TimeUnit.SECONDS.convert(1000000000L*t,
- TimeUnit.NANOSECONDS));
+ SECONDS.convert(1000000000L*t, NANOSECONDS));
assertEquals(1000L*t*60*60*24,
- TimeUnit.MILLISECONDS.convert(t,
- TimeUnit.DAYS));
+ MILLISECONDS.convert(t, DAYS));
assertEquals(1000L*t*60*60,
- TimeUnit.MILLISECONDS.convert(t,
- TimeUnit.HOURS));
+ MILLISECONDS.convert(t, HOURS));
assertEquals(1000L*t*60,
- TimeUnit.MILLISECONDS.convert(t,
- TimeUnit.MINUTES));
+ MILLISECONDS.convert(t, MINUTES));
assertEquals(1000L*t,
- TimeUnit.MILLISECONDS.convert(t,
- TimeUnit.SECONDS));
+ MILLISECONDS.convert(t, SECONDS));
assertEquals(t,
- TimeUnit.MILLISECONDS.convert(t,
- TimeUnit.MILLISECONDS));
+ MILLISECONDS.convert(t, MILLISECONDS));
assertEquals(t,
- TimeUnit.MILLISECONDS.convert(1000L*t,
- TimeUnit.MICROSECONDS));
+ MILLISECONDS.convert(1000L*t, MICROSECONDS));
assertEquals(t,
- TimeUnit.MILLISECONDS.convert(1000000L*t,
- TimeUnit.NANOSECONDS));
+ MILLISECONDS.convert(1000000L*t, NANOSECONDS));
assertEquals(1000000L*t*60*60*24,
- TimeUnit.MICROSECONDS.convert(t,
- TimeUnit.DAYS));
+ MICROSECONDS.convert(t, DAYS));
assertEquals(1000000L*t*60*60,
- TimeUnit.MICROSECONDS.convert(t,
- TimeUnit.HOURS));
+ MICROSECONDS.convert(t, HOURS));
assertEquals(1000000L*t*60,
- TimeUnit.MICROSECONDS.convert(t,
- TimeUnit.MINUTES));
+ MICROSECONDS.convert(t, MINUTES));
assertEquals(1000000L*t,
- TimeUnit.MICROSECONDS.convert(t,
- TimeUnit.SECONDS));
+ MICROSECONDS.convert(t, SECONDS));
assertEquals(1000L*t,
- TimeUnit.MICROSECONDS.convert(t,
- TimeUnit.MILLISECONDS));
+ MICROSECONDS.convert(t, MILLISECONDS));
assertEquals(t,
- TimeUnit.MICROSECONDS.convert(t,
- TimeUnit.MICROSECONDS));
+ MICROSECONDS.convert(t, MICROSECONDS));
assertEquals(t,
- TimeUnit.MICROSECONDS.convert(1000L*t,
- TimeUnit.NANOSECONDS));
+ MICROSECONDS.convert(1000L*t, NANOSECONDS));
assertEquals(1000000000L*t*60*60*24,
- TimeUnit.NANOSECONDS.convert(t,
- TimeUnit.DAYS));
+ NANOSECONDS.convert(t, DAYS));
assertEquals(1000000000L*t*60*60,
- TimeUnit.NANOSECONDS.convert(t,
- TimeUnit.HOURS));
+ NANOSECONDS.convert(t, HOURS));
assertEquals(1000000000L*t*60,
- TimeUnit.NANOSECONDS.convert(t,
- TimeUnit.MINUTES));
+ NANOSECONDS.convert(t, MINUTES));
assertEquals(1000000000L*t,
- TimeUnit.NANOSECONDS.convert(t,
- TimeUnit.SECONDS));
+ NANOSECONDS.convert(t, SECONDS));
assertEquals(1000000L*t,
- TimeUnit.NANOSECONDS.convert(t,
- TimeUnit.MILLISECONDS));
+ NANOSECONDS.convert(t, MILLISECONDS));
assertEquals(1000L*t,
- TimeUnit.NANOSECONDS.convert(t,
- TimeUnit.MICROSECONDS));
+ NANOSECONDS.convert(t, MICROSECONDS));
assertEquals(t,
- TimeUnit.NANOSECONDS.convert(t,
- TimeUnit.NANOSECONDS));
+ NANOSECONDS.convert(t, NANOSECONDS));
}
}
@@ -118,19 +109,19 @@ public class TimeUnitTest extends JSR166TestCase {
public void testToNanos() {
for (long t = 0; t < 88888; ++t) {
assertEquals(t*1000000000L*60*60*24,
- TimeUnit.DAYS.toNanos(t));
+ DAYS.toNanos(t));
assertEquals(t*1000000000L*60*60,
- TimeUnit.HOURS.toNanos(t));
+ HOURS.toNanos(t));
assertEquals(t*1000000000L*60,
- TimeUnit.MINUTES.toNanos(t));
+ MINUTES.toNanos(t));
assertEquals(1000000000L*t,
- TimeUnit.SECONDS.toNanos(t));
+ SECONDS.toNanos(t));
assertEquals(1000000L*t,
- TimeUnit.MILLISECONDS.toNanos(t));
+ MILLISECONDS.toNanos(t));
assertEquals(1000L*t,
- TimeUnit.MICROSECONDS.toNanos(t));
+ MICROSECONDS.toNanos(t));
assertEquals(t,
- TimeUnit.NANOSECONDS.toNanos(t));
+ NANOSECONDS.toNanos(t));
}
}
@@ -141,19 +132,19 @@ public class TimeUnitTest extends JSR166TestCase {
public void testToMicros() {
for (long t = 0; t < 88888; ++t) {
assertEquals(t*1000000L*60*60*24,
- TimeUnit.DAYS.toMicros(t));
+ DAYS.toMicros(t));
assertEquals(t*1000000L*60*60,
- TimeUnit.HOURS.toMicros(t));
+ HOURS.toMicros(t));
assertEquals(t*1000000L*60,
- TimeUnit.MINUTES.toMicros(t));
+ MINUTES.toMicros(t));
assertEquals(1000000L*t,
- TimeUnit.SECONDS.toMicros(t));
+ SECONDS.toMicros(t));
assertEquals(1000L*t,
- TimeUnit.MILLISECONDS.toMicros(t));
+ MILLISECONDS.toMicros(t));
assertEquals(t,
- TimeUnit.MICROSECONDS.toMicros(t));
+ MICROSECONDS.toMicros(t));
assertEquals(t,
- TimeUnit.NANOSECONDS.toMicros(t*1000L));
+ NANOSECONDS.toMicros(t*1000L));
}
}
@@ -164,19 +155,19 @@ public class TimeUnitTest extends JSR166TestCase {
public void testToMillis() {
for (long t = 0; t < 88888; ++t) {
assertEquals(t*1000L*60*60*24,
- TimeUnit.DAYS.toMillis(t));
+ DAYS.toMillis(t));
assertEquals(t*1000L*60*60,
- TimeUnit.HOURS.toMillis(t));
+ HOURS.toMillis(t));
assertEquals(t*1000L*60,
- TimeUnit.MINUTES.toMillis(t));
+ MINUTES.toMillis(t));
assertEquals(1000L*t,
- TimeUnit.SECONDS.toMillis(t));
+ SECONDS.toMillis(t));
assertEquals(t,
- TimeUnit.MILLISECONDS.toMillis(t));
+ MILLISECONDS.toMillis(t));
assertEquals(t,
- TimeUnit.MICROSECONDS.toMillis(t*1000L));
+ MICROSECONDS.toMillis(t*1000L));
assertEquals(t,
- TimeUnit.NANOSECONDS.toMillis(t*1000000L));
+ NANOSECONDS.toMillis(t*1000000L));
}
}
@@ -187,19 +178,19 @@ public class TimeUnitTest extends JSR166TestCase {
public void testToSeconds() {
for (long t = 0; t < 88888; ++t) {
assertEquals(t*60*60*24,
- TimeUnit.DAYS.toSeconds(t));
+ DAYS.toSeconds(t));
assertEquals(t*60*60,
- TimeUnit.HOURS.toSeconds(t));
+ HOURS.toSeconds(t));
assertEquals(t*60,
- TimeUnit.MINUTES.toSeconds(t));
+ MINUTES.toSeconds(t));
assertEquals(t,
- TimeUnit.SECONDS.toSeconds(t));
+ SECONDS.toSeconds(t));
assertEquals(t,
- TimeUnit.MILLISECONDS.toSeconds(t*1000L));
+ MILLISECONDS.toSeconds(t*1000L));
assertEquals(t,
- TimeUnit.MICROSECONDS.toSeconds(t*1000000L));
+ MICROSECONDS.toSeconds(t*1000000L));
assertEquals(t,
- TimeUnit.NANOSECONDS.toSeconds(t*1000000000L));
+ NANOSECONDS.toSeconds(t*1000000000L));
}
}
@@ -210,19 +201,19 @@ public class TimeUnitTest extends JSR166TestCase {
public void testToMinutes() {
for (long t = 0; t < 88888; ++t) {
assertEquals(t*60*24,
- TimeUnit.DAYS.toMinutes(t));
+ DAYS.toMinutes(t));
assertEquals(t*60,
- TimeUnit.HOURS.toMinutes(t));
+ HOURS.toMinutes(t));
assertEquals(t,
- TimeUnit.MINUTES.toMinutes(t));
+ MINUTES.toMinutes(t));
assertEquals(t,
- TimeUnit.SECONDS.toMinutes(t*60));
+ SECONDS.toMinutes(t*60));
assertEquals(t,
- TimeUnit.MILLISECONDS.toMinutes(t*1000L*60));
+ MILLISECONDS.toMinutes(t*1000L*60));
assertEquals(t,
- TimeUnit.MICROSECONDS.toMinutes(t*1000000L*60));
+ MICROSECONDS.toMinutes(t*1000000L*60));
assertEquals(t,
- TimeUnit.NANOSECONDS.toMinutes(t*1000000000L*60));
+ NANOSECONDS.toMinutes(t*1000000000L*60));
}
}
@@ -233,19 +224,19 @@ public class TimeUnitTest extends JSR166TestCase {
public void testToHours() {
for (long t = 0; t < 88888; ++t) {
assertEquals(t*24,
- TimeUnit.DAYS.toHours(t));
+ DAYS.toHours(t));
assertEquals(t,
- TimeUnit.HOURS.toHours(t));
+ HOURS.toHours(t));
assertEquals(t,
- TimeUnit.MINUTES.toHours(t*60));
+ MINUTES.toHours(t*60));
assertEquals(t,
- TimeUnit.SECONDS.toHours(t*60*60));
+ SECONDS.toHours(t*60*60));
assertEquals(t,
- TimeUnit.MILLISECONDS.toHours(t*1000L*60*60));
+ MILLISECONDS.toHours(t*1000L*60*60));
assertEquals(t,
- TimeUnit.MICROSECONDS.toHours(t*1000000L*60*60));
+ MICROSECONDS.toHours(t*1000000L*60*60));
assertEquals(t,
- TimeUnit.NANOSECONDS.toHours(t*1000000000L*60*60));
+ NANOSECONDS.toHours(t*1000000000L*60*60));
}
}
@@ -256,19 +247,19 @@ public class TimeUnitTest extends JSR166TestCase {
public void testToDays() {
for (long t = 0; t < 88888; ++t) {
assertEquals(t,
- TimeUnit.DAYS.toDays(t));
+ DAYS.toDays(t));
assertEquals(t,
- TimeUnit.HOURS.toDays(t*24));
+ HOURS.toDays(t*24));
assertEquals(t,
- TimeUnit.MINUTES.toDays(t*60*24));
+ MINUTES.toDays(t*60*24));
assertEquals(t,
- TimeUnit.SECONDS.toDays(t*60*60*24));
+ SECONDS.toDays(t*60*60*24));
assertEquals(t,
- TimeUnit.MILLISECONDS.toDays(t*1000L*60*60*24));
+ MILLISECONDS.toDays(t*1000L*60*60*24));
assertEquals(t,
- TimeUnit.MICROSECONDS.toDays(t*1000000L*60*60*24));
+ MICROSECONDS.toDays(t*1000000L*60*60*24));
assertEquals(t,
- TimeUnit.NANOSECONDS.toDays(t*1000000000L*60*60*24));
+ NANOSECONDS.toDays(t*1000000000L*60*60*24));
}
}
@@ -278,29 +269,21 @@ public class TimeUnitTest extends JSR166TestCase {
*/
public void testConvertSaturate() {
assertEquals(Long.MAX_VALUE,
- TimeUnit.NANOSECONDS.convert(Long.MAX_VALUE / 2,
- TimeUnit.SECONDS));
+ NANOSECONDS.convert(Long.MAX_VALUE / 2, SECONDS));
assertEquals(Long.MIN_VALUE,
- TimeUnit.NANOSECONDS.convert(-Long.MAX_VALUE / 4,
- TimeUnit.SECONDS));
+ NANOSECONDS.convert(-Long.MAX_VALUE / 4, SECONDS));
assertEquals(Long.MAX_VALUE,
- TimeUnit.NANOSECONDS.convert(Long.MAX_VALUE / 2,
- TimeUnit.MINUTES));
+ NANOSECONDS.convert(Long.MAX_VALUE / 2, MINUTES));
assertEquals(Long.MIN_VALUE,
- TimeUnit.NANOSECONDS.convert(-Long.MAX_VALUE / 4,
- TimeUnit.MINUTES));
+ NANOSECONDS.convert(-Long.MAX_VALUE / 4, MINUTES));
assertEquals(Long.MAX_VALUE,
- TimeUnit.NANOSECONDS.convert(Long.MAX_VALUE / 2,
- TimeUnit.HOURS));
+ NANOSECONDS.convert(Long.MAX_VALUE / 2, HOURS));
assertEquals(Long.MIN_VALUE,
- TimeUnit.NANOSECONDS.convert(-Long.MAX_VALUE / 4,
- TimeUnit.HOURS));
+ NANOSECONDS.convert(-Long.MAX_VALUE / 4, HOURS));
assertEquals(Long.MAX_VALUE,
- TimeUnit.NANOSECONDS.convert(Long.MAX_VALUE / 2,
- TimeUnit.DAYS));
+ NANOSECONDS.convert(Long.MAX_VALUE / 2, DAYS));
assertEquals(Long.MIN_VALUE,
- TimeUnit.NANOSECONDS.convert(-Long.MAX_VALUE / 4,
- TimeUnit.DAYS));
+ NANOSECONDS.convert(-Long.MAX_VALUE / 4, DAYS));
}
/**
@@ -309,23 +292,23 @@ public class TimeUnitTest extends JSR166TestCase {
*/
public void testToNanosSaturate() {
assertEquals(Long.MAX_VALUE,
- TimeUnit.MILLISECONDS.toNanos(Long.MAX_VALUE / 2));
+ MILLISECONDS.toNanos(Long.MAX_VALUE / 2));
assertEquals(Long.MIN_VALUE,
- TimeUnit.MILLISECONDS.toNanos(-Long.MAX_VALUE / 3));
+ MILLISECONDS.toNanos(-Long.MAX_VALUE / 3));
}
/**
* toString returns name of unit
*/
public void testToString() {
- assertEquals("SECONDS", TimeUnit.SECONDS.toString());
+ assertEquals("SECONDS", SECONDS.toString());
}
/**
* name returns name of unit
*/
public void testName() {
- assertEquals("SECONDS", TimeUnit.SECONDS.name());
+ assertEquals("SECONDS", SECONDS.name());
}
/**
@@ -336,7 +319,7 @@ public class TimeUnitTest extends JSR166TestCase {
Thread t = newStartedThread(new CheckedRunnable() {
public void realRun() throws InterruptedException {
Object o = new Object();
- TimeUnit tu = TimeUnit.MILLISECONDS;
+ TimeUnit tu = MILLISECONDS;
try {
tu.timedWait(o, LONG_DELAY_MS);
@@ -355,7 +338,7 @@ public class TimeUnitTest extends JSR166TestCase {
Thread t = newStartedThread(new CheckedRunnable() {
public void realRun() throws InterruptedException {
Object o = new Object();
- TimeUnit tu = TimeUnit.MILLISECONDS;
+ TimeUnit tu = MILLISECONDS;
Thread.currentThread().interrupt();
try {
@@ -393,7 +376,7 @@ public class TimeUnitTest extends JSR166TestCase {
}});
final Thread t = newStartedThread(new CheckedRunnable() {
public void realRun() throws InterruptedException {
- TimeUnit tu = TimeUnit.MILLISECONDS;
+ TimeUnit tu = MILLISECONDS;
Thread.currentThread().interrupt();
try {
tu.timedJoin(s, LONG_DELAY_MS);
@@ -424,7 +407,7 @@ public class TimeUnitTest extends JSR166TestCase {
final CountDownLatch pleaseInterrupt = new CountDownLatch(1);
Thread t = newStartedThread(new CheckedRunnable() {
public void realRun() throws InterruptedException {
- TimeUnit tu = TimeUnit.MILLISECONDS;
+ TimeUnit tu = MILLISECONDS;
Thread.currentThread().interrupt();
try {
tu.sleep(LONG_DELAY_MS);
@@ -450,7 +433,7 @@ public class TimeUnitTest extends JSR166TestCase {
* a deserialized serialized unit is the same instance
*/
public void testSerialization() throws Exception {
- TimeUnit x = TimeUnit.MILLISECONDS;
+ TimeUnit x = MILLISECONDS;
assertSame(x, serialClone(x));
}
diff --git a/jsr166-tests/src/test/java/jsr166/TreeMapTest.java b/jsr166-tests/src/test/java/jsr166/TreeMapTest.java
index 87baa1a..afc73de 100644
--- a/jsr166-tests/src/test/java/jsr166/TreeMapTest.java
+++ b/jsr166-tests/src/test/java/jsr166/TreeMapTest.java
@@ -6,10 +6,31 @@
package jsr166;
-import junit.framework.*;
-import java.util.*;
+import java.util.Arrays;
+import java.util.BitSet;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.NavigableMap;
+import java.util.NavigableSet;
+import java.util.NoSuchElementException;
+import java.util.Random;
+import java.util.Set;
+import java.util.TreeMap;
+
+import junit.framework.Test;
+import junit.framework.TestSuite;
public class TreeMapTest extends JSR166TestCase {
+ // android-note: Removed because the CTS runner does a bad job of
+ // retrying tests that have suite() declarations.
+ //
+ // public static void main(String[] args) {
+ // main(suite(), args);
+ // }
+ // public static Test suite() {
+ // return new TestSuite(...);
+ // }
/**
* Returns a new map from Integers 1-5 to Strings "A"-"E".
@@ -559,8 +580,8 @@ public class TreeMapTest extends JSR166TestCase {
* get(null) of nonempty map throws NPE
*/
public void testGet_NullPointerException() {
+ TreeMap c = map5();
try {
- TreeMap c = map5();
c.get(null);
shouldThrow();
} catch (NullPointerException success) {}
@@ -570,8 +591,8 @@ public class TreeMapTest extends JSR166TestCase {
* containsKey(null) of nonempty map throws NPE
*/
public void testContainsKey_NullPointerException() {
+ TreeMap c = map5();
try {
- TreeMap c = map5();
c.containsKey(null);
shouldThrow();
} catch (NullPointerException success) {}
@@ -581,9 +602,9 @@ public class TreeMapTest extends JSR166TestCase {
* remove(null) throws NPE for nonempty map
*/
public void testRemove1_NullPointerException() {
+ TreeMap c = new TreeMap();
+ c.put("sadsdf", "asdads");
try {
- TreeMap c = new TreeMap();
- c.put("sadsdf", "asdads");
c.remove(null);
shouldThrow();
} catch (NullPointerException success) {}
@@ -819,7 +840,7 @@ public class TreeMapTest extends JSR166TestCase {
// Add entries till we're back to original size
while (map.size() < size) {
int key = min + rnd.nextInt(rangeSize);
- assertTrue(key >= min && key<= max);
+ assertTrue(key >= min && key <= max);
put(map, key);
}
}
@@ -844,7 +865,7 @@ public class TreeMapTest extends JSR166TestCase {
// Add entries till we're back to original size
while (map.size() < size) {
int key = min - 5 + rnd.nextInt(rangeSize + 10);
- if (key >= min && key<= max) {
+ if (key >= min && key <= max) {
put(map, key);
} else {
try {
diff --git a/jsr166-tests/src/test/java/jsr166/TreeSetTest.java b/jsr166-tests/src/test/java/jsr166/TreeSetTest.java
index 2957019..a935637 100644
--- a/jsr166-tests/src/test/java/jsr166/TreeSetTest.java
+++ b/jsr166-tests/src/test/java/jsr166/TreeSetTest.java
@@ -6,7 +6,6 @@
package jsr166;
-import junit.framework.*;
import java.util.Arrays;
import java.util.BitSet;
import java.util.Collection;
@@ -19,7 +18,19 @@ import java.util.Set;
import java.util.SortedSet;
import java.util.TreeSet;
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
public class TreeSetTest extends JSR166TestCase {
+ // android-note: Removed because the CTS runner does a bad job of
+ // retrying tests that have suite() declarations.
+ //
+ // public static void main(String[] args) {
+ // main(suite(), args);
+ // }
+ // public static Test suite() {
+ // return new TestSuite(...);
+ // }
static class MyReverseComparator implements Comparator {
public int compare(Object x, Object y) {
@@ -39,9 +50,9 @@ public class TreeSetTest extends JSR166TestCase {
private TreeSet<Integer> populatedSet(int n) {
TreeSet<Integer> q = new TreeSet<Integer>();
assertTrue(q.isEmpty());
- for (int i = n-1; i >= 0; i-=2)
+ for (int i = n-1; i >= 0; i -= 2)
assertTrue(q.add(new Integer(i)));
- for (int i = (n & 1); i < n; i+=2)
+ for (int i = (n & 1); i < n; i += 2)
assertTrue(q.add(new Integer(i)));
assertFalse(q.isEmpty());
assertEquals(n, q.size());
@@ -75,7 +86,7 @@ public class TreeSetTest extends JSR166TestCase {
*/
public void testConstructor3() {
try {
- TreeSet q = new TreeSet((Collection)null);
+ new TreeSet((Collection)null);
shouldThrow();
} catch (NullPointerException success) {}
}
@@ -86,7 +97,7 @@ public class TreeSetTest extends JSR166TestCase {
public void testConstructor4() {
try {
Integer[] ints = new Integer[SIZE];
- TreeSet q = new TreeSet(Arrays.asList(ints));
+ new TreeSet(Arrays.asList(ints));
shouldThrow();
} catch (NullPointerException success) {}
}
@@ -99,7 +110,7 @@ public class TreeSetTest extends JSR166TestCase {
Integer[] ints = new Integer[SIZE];
for (int i = 0; i < SIZE-1; ++i)
ints[i] = new Integer(i);
- TreeSet q = new TreeSet(Arrays.asList(ints));
+ new TreeSet(Arrays.asList(ints));
shouldThrow();
} catch (NullPointerException success) {}
}
@@ -164,8 +175,8 @@ public class TreeSetTest extends JSR166TestCase {
* add(null) throws NPE if nonempty
*/
public void testAddNull() {
+ TreeSet q = populatedSet(SIZE);
try {
- TreeSet q = populatedSet(SIZE);
q.add(null);
shouldThrow();
} catch (NullPointerException success) {}
@@ -193,9 +204,8 @@ public class TreeSetTest extends JSR166TestCase {
* Add of non-Comparable throws CCE
*/
public void testAddNonComparable() {
+ TreeSet q = new TreeSet();
try {
- TreeSet q = new TreeSet();
- q.add(new Object());
q.add(new Object());
q.add(new Object());
shouldThrow();
@@ -206,8 +216,8 @@ public class TreeSetTest extends JSR166TestCase {
* addAll(null) throws NPE
*/
public void testAddAll1() {
+ TreeSet q = new TreeSet();
try {
- TreeSet q = new TreeSet();
q.addAll(null);
shouldThrow();
} catch (NullPointerException success) {}
@@ -217,9 +227,9 @@ public class TreeSetTest extends JSR166TestCase {
* addAll of a collection with null elements throws NPE
*/
public void testAddAll2() {
+ TreeSet q = new TreeSet();
+ Integer[] ints = new Integer[SIZE];
try {
- TreeSet q = new TreeSet();
- Integer[] ints = new Integer[SIZE];
q.addAll(Arrays.asList(ints));
shouldThrow();
} catch (NullPointerException success) {}
@@ -230,11 +240,11 @@ public class TreeSetTest extends JSR166TestCase {
* possibly adding some elements
*/
public void testAddAll3() {
+ TreeSet q = new TreeSet();
+ Integer[] ints = new Integer[SIZE];
+ for (int i = 0; i < SIZE-1; ++i)
+ ints[i] = new Integer(i);
try {
- TreeSet q = new TreeSet();
- Integer[] ints = new Integer[SIZE];
- for (int i = 0; i < SIZE-1; ++i)
- ints[i] = new Integer(i);
q.addAll(Arrays.asList(ints));
shouldThrow();
} catch (NullPointerException success) {}
@@ -282,13 +292,13 @@ public class TreeSetTest extends JSR166TestCase {
*/
public void testRemoveElement() {
TreeSet q = populatedSet(SIZE);
- for (int i = 1; i < SIZE; i+=2) {
+ for (int i = 1; i < SIZE; i += 2) {
assertTrue(q.contains(i));
assertTrue(q.remove(i));
assertFalse(q.contains(i));
assertTrue(q.contains(i-1));
}
- for (int i = 0; i < SIZE; i+=2) {
+ for (int i = 0; i < SIZE; i += 2) {
assertTrue(q.contains(i));
assertTrue(q.remove(i));
assertFalse(q.contains(i));
@@ -367,8 +377,8 @@ public class TreeSetTest extends JSR166TestCase {
assertTrue(q.removeAll(p));
assertEquals(SIZE-i, q.size());
for (int j = 0; j < i; ++j) {
- Integer I = (Integer)(p.pollFirst());
- assertFalse(q.contains(I));
+ Integer x = (Integer)(p.pollFirst());
+ assertFalse(q.contains(x));
}
}
}
@@ -472,27 +482,19 @@ public class TreeSetTest extends JSR166TestCase {
*/
public void testIterator() {
TreeSet q = populatedSet(SIZE);
- int i = 0;
Iterator it = q.iterator();
- while (it.hasNext()) {
+ int i;
+ for (i = 0; it.hasNext(); i++)
assertTrue(q.contains(it.next()));
- ++i;
- }
assertEquals(i, SIZE);
+ assertIteratorExhausted(it);
}
/**
* iterator of empty set has no elements
*/
public void testEmptyIterator() {
- TreeSet q = new TreeSet();
- int i = 0;
- Iterator it = q.iterator();
- while (it.hasNext()) {
- assertTrue(q.contains(it.next()));
- ++i;
- }
- assertEquals(0, i);
+ assertIteratorExhausted(new TreeSet().iterator());
}
/**
@@ -732,7 +734,7 @@ public class TreeSetTest extends JSR166TestCase {
// Add entries till we're back to original size
while (set.size() < size) {
int element = min + rnd.nextInt(rangeSize);
- assertTrue(element >= min && element<= max);
+ assertTrue(element >= min && element <= max);
put(set, element);
}
}
@@ -757,7 +759,7 @@ public class TreeSetTest extends JSR166TestCase {
// Add entries till we're back to original size
while (set.size() < size) {
int element = min - 5 + rnd.nextInt(rangeSize + 10);
- if (element >= min && element<= max) {
+ if (element >= min && element <= max) {
put(set, element);
} else {
try {
diff --git a/jsr166-tests/src/test/java/jsr166/TreeSubMapTest.java b/jsr166-tests/src/test/java/jsr166/TreeSubMapTest.java
index 17201f3..18a9e37 100644
--- a/jsr166-tests/src/test/java/jsr166/TreeSubMapTest.java
+++ b/jsr166-tests/src/test/java/jsr166/TreeSubMapTest.java
@@ -6,10 +6,29 @@
package jsr166;
-import junit.framework.*;
-import java.util.*;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.NavigableMap;
+import java.util.Set;
+import java.util.SortedMap;
+import java.util.TreeMap;
+
+import junit.framework.Test;
+import junit.framework.TestSuite;
public class TreeSubMapTest extends JSR166TestCase {
+ // android-note: Removed because the CTS runner does a bad job of
+ // retrying tests that have suite() declarations.
+ //
+ // public static void main(String[] args) {
+ // main(suite(), args);
+ // }
+ // public static Test suite() {
+ // return new TestSuite(...);
+ // }
/**
* Returns a new map from Integers 1-5 to Strings "A"-"E".
@@ -378,8 +397,8 @@ public class TreeSubMapTest extends JSR166TestCase {
* get(null) of nonempty map throws NPE
*/
public void testGet_NullPointerException() {
+ NavigableMap c = map5();
try {
- NavigableMap c = map5();
c.get(null);
shouldThrow();
} catch (NullPointerException success) {}
@@ -389,8 +408,8 @@ public class TreeSubMapTest extends JSR166TestCase {
* containsKey(null) of nonempty map throws NPE
*/
public void testContainsKey_NullPointerException() {
+ NavigableMap c = map5();
try {
- NavigableMap c = map5();
c.containsKey(null);
shouldThrow();
} catch (NullPointerException success) {}
@@ -400,8 +419,8 @@ public class TreeSubMapTest extends JSR166TestCase {
* put(null,x) throws NPE
*/
public void testPut1_NullPointerException() {
+ NavigableMap c = map5();
try {
- NavigableMap c = map5();
c.put(null, "whatever");
shouldThrow();
} catch (NullPointerException success) {}
@@ -411,8 +430,8 @@ public class TreeSubMapTest extends JSR166TestCase {
* remove(null) throws NPE
*/
public void testRemove1_NullPointerException() {
+ NavigableMap c = map5();
try {
- NavigableMap c = map5();
c.remove(null);
shouldThrow();
} catch (NullPointerException success) {}
@@ -927,8 +946,8 @@ public class TreeSubMapTest extends JSR166TestCase {
* get(null) of nonempty map throws NPE
*/
public void testDescendingGet_NullPointerException() {
+ NavigableMap c = dmap5();
try {
- NavigableMap c = dmap5();
c.get(null);
shouldThrow();
} catch (NullPointerException success) {}
@@ -938,8 +957,8 @@ public class TreeSubMapTest extends JSR166TestCase {
* put(null,x) throws NPE
*/
public void testDescendingPut1_NullPointerException() {
+ NavigableMap c = dmap5();
try {
- NavigableMap c = dmap5();
c.put(null, "whatever");
shouldThrow();
} catch (NullPointerException success) {}
diff --git a/jsr166-tests/src/test/java/jsr166/TreeSubSetTest.java b/jsr166-tests/src/test/java/jsr166/TreeSubSetTest.java
index ba61748..5398c4e 100644
--- a/jsr166-tests/src/test/java/jsr166/TreeSubSetTest.java
+++ b/jsr166-tests/src/test/java/jsr166/TreeSubSetTest.java
@@ -6,16 +6,27 @@
package jsr166;
-import junit.framework.*;
import java.util.Arrays;
import java.util.Comparator;
import java.util.Iterator;
import java.util.NavigableSet;
-import java.util.SortedSet;
import java.util.Set;
+import java.util.SortedSet;
import java.util.TreeSet;
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
public class TreeSubSetTest extends JSR166TestCase {
+ // android-note: Removed because the CTS runner does a bad job of
+ // retrying tests that have suite() declarations.
+ //
+ // public static void main(String[] args) {
+ // main(suite(), args);
+ // }
+ // public static Test suite() {
+ // return new TestSuite(...);
+ // }
static class MyReverseComparator implements Comparator {
public int compare(Object x, Object y) {
@@ -31,9 +42,9 @@ public class TreeSubSetTest extends JSR166TestCase {
TreeSet<Integer> q = new TreeSet<Integer>();
assertTrue(q.isEmpty());
- for (int i = n-1; i >= 0; i-=2)
+ for (int i = n-1; i >= 0; i -= 2)
assertTrue(q.add(new Integer(i)));
- for (int i = (n & 1); i < n; i+=2)
+ for (int i = (n & 1); i < n; i += 2)
assertTrue(q.add(new Integer(i)));
assertTrue(q.add(new Integer(-n)));
assertTrue(q.add(new Integer(n)));
@@ -126,8 +137,8 @@ public class TreeSubSetTest extends JSR166TestCase {
* add(null) throws NPE
*/
public void testAddNull() {
+ NavigableSet q = set0();
try {
- NavigableSet q = set0();
q.add(null);
shouldThrow();
} catch (NullPointerException success) {}
@@ -154,9 +165,8 @@ public class TreeSubSetTest extends JSR166TestCase {
* Add of non-Comparable throws CCE
*/
public void testAddNonComparable() {
+ NavigableSet q = set0();
try {
- NavigableSet q = set0();
- q.add(new Object());
q.add(new Object());
q.add(new Object());
shouldThrow();
@@ -167,8 +177,8 @@ public class TreeSubSetTest extends JSR166TestCase {
* addAll(null) throws NPE
*/
public void testAddAll1() {
+ NavigableSet q = set0();
try {
- NavigableSet q = set0();
q.addAll(null);
shouldThrow();
} catch (NullPointerException success) {}
@@ -178,9 +188,9 @@ public class TreeSubSetTest extends JSR166TestCase {
* addAll of a collection with null elements throws NPE
*/
public void testAddAll2() {
+ NavigableSet q = set0();
+ Integer[] ints = new Integer[SIZE];
try {
- NavigableSet q = set0();
- Integer[] ints = new Integer[SIZE];
q.addAll(Arrays.asList(ints));
shouldThrow();
} catch (NullPointerException success) {}
@@ -191,11 +201,11 @@ public class TreeSubSetTest extends JSR166TestCase {
* possibly adding some elements
*/
public void testAddAll3() {
+ NavigableSet q = set0();
+ Integer[] ints = new Integer[SIZE];
+ for (int i = 0; i < SIZE-1; ++i)
+ ints[i] = new Integer(i+SIZE);
try {
- NavigableSet q = set0();
- Integer[] ints = new Integer[SIZE];
- for (int i = 0; i < SIZE-1; ++i)
- ints[i] = new Integer(i+SIZE);
q.addAll(Arrays.asList(ints));
shouldThrow();
} catch (NullPointerException success) {}
@@ -232,13 +242,13 @@ public class TreeSubSetTest extends JSR166TestCase {
*/
public void testRemoveElement() {
NavigableSet q = populatedSet(SIZE);
- for (int i = 1; i < SIZE; i+=2) {
+ for (int i = 1; i < SIZE; i += 2) {
assertTrue(q.contains(i));
assertTrue(q.remove(i));
assertFalse(q.contains(i));
assertTrue(q.contains(i-1));
}
- for (int i = 0; i < SIZE; i+=2) {
+ for (int i = 0; i < SIZE; i += 2) {
assertTrue(q.contains(i));
assertTrue(q.remove(i));
assertFalse(q.contains(i));
@@ -317,8 +327,8 @@ public class TreeSubSetTest extends JSR166TestCase {
assertTrue(q.removeAll(p));
assertEquals(SIZE-i, q.size());
for (int j = 0; j < i; ++j) {
- Integer I = (Integer)(p.pollFirst());
- assertFalse(q.contains(I));
+ Integer x = (Integer)(p.pollFirst());
+ assertFalse(q.contains(x));
}
}
}
@@ -422,27 +432,19 @@ public class TreeSubSetTest extends JSR166TestCase {
*/
public void testIterator() {
NavigableSet q = populatedSet(SIZE);
- int i = 0;
Iterator it = q.iterator();
- while (it.hasNext()) {
+ int i;
+ for (i = 0; it.hasNext(); i++)
assertTrue(q.contains(it.next()));
- ++i;
- }
assertEquals(i, SIZE);
+ assertIteratorExhausted(it);
}
/**
* iterator of empty set has no elements
*/
public void testEmptyIterator() {
- NavigableSet q = set0();
- int i = 0;
- Iterator it = q.iterator();
- while (it.hasNext()) {
- assertTrue(q.contains(it.next()));
- ++i;
- }
- assertEquals(0, i);
+ assertIteratorExhausted(set0().iterator());
}
/**
@@ -648,9 +650,8 @@ public class TreeSubSetTest extends JSR166TestCase {
* Add of non-Comparable throws CCE
*/
public void testDescendingAddNonComparable() {
+ NavigableSet q = dset0();
try {
- NavigableSet q = dset0();
- q.add(new Object());
q.add(new Object());
q.add(new Object());
shouldThrow();
@@ -661,8 +662,8 @@ public class TreeSubSetTest extends JSR166TestCase {
* addAll(null) throws NPE
*/
public void testDescendingAddAll1() {
+ NavigableSet q = dset0();
try {
- NavigableSet q = dset0();
q.addAll(null);
shouldThrow();
} catch (NullPointerException success) {}
@@ -672,9 +673,9 @@ public class TreeSubSetTest extends JSR166TestCase {
* addAll of a collection with null elements throws NPE
*/
public void testDescendingAddAll2() {
+ NavigableSet q = dset0();
+ Integer[] ints = new Integer[SIZE];
try {
- NavigableSet q = dset0();
- Integer[] ints = new Integer[SIZE];
q.addAll(Arrays.asList(ints));
shouldThrow();
} catch (NullPointerException success) {}
@@ -685,11 +686,11 @@ public class TreeSubSetTest extends JSR166TestCase {
* possibly adding some elements
*/
public void testDescendingAddAll3() {
+ NavigableSet q = dset0();
+ Integer[] ints = new Integer[SIZE];
+ for (int i = 0; i < SIZE-1; ++i)
+ ints[i] = new Integer(i+SIZE);
try {
- NavigableSet q = dset0();
- Integer[] ints = new Integer[SIZE];
- for (int i = 0; i < SIZE-1; ++i)
- ints[i] = new Integer(i+SIZE);
q.addAll(Arrays.asList(ints));
shouldThrow();
} catch (NullPointerException success) {}
@@ -726,10 +727,10 @@ public class TreeSubSetTest extends JSR166TestCase {
*/
public void testDescendingRemoveElement() {
NavigableSet q = populatedSet(SIZE);
- for (int i = 1; i < SIZE; i+=2) {
+ for (int i = 1; i < SIZE; i += 2) {
assertTrue(q.remove(new Integer(i)));
}
- for (int i = 0; i < SIZE; i+=2) {
+ for (int i = 0; i < SIZE; i += 2) {
assertTrue(q.remove(new Integer(i)));
assertFalse(q.remove(new Integer(i+1)));
}
@@ -805,8 +806,8 @@ public class TreeSubSetTest extends JSR166TestCase {
assertTrue(q.removeAll(p));
assertEquals(SIZE-i, q.size());
for (int j = 0; j < i; ++j) {
- Integer I = (Integer)(p.pollFirst());
- assertFalse(q.contains(I));
+ Integer x = (Integer)(p.pollFirst());
+ assertFalse(q.contains(x));
}
}
}
diff --git a/libart/src/main/java/dalvik/system/TransactionAbortError.java b/libart/src/main/java/dalvik/system/TransactionAbortError.java
new file mode 100644
index 0000000..cfe4ca2
--- /dev/null
+++ b/libart/src/main/java/dalvik/system/TransactionAbortError.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dalvik.system;
+
+/**
+ * An exception only used by the compiler to abort a transaction.
+ *
+ * @hide
+ */
+final class TransactionAbortError extends InternalError {
+ /**
+ * Constructs a new {@code TransactionAbortError} with its stack trace filled in.
+ */
+ private TransactionAbortError() {
+ }
+
+ /**
+ * Constructs a new {@code TransactionAbortError} with its stack trace and detail
+ * message filled in.
+ *
+ * @param detailMessage the detail message for the exception.
+ */
+ private TransactionAbortError(String detailMessage) {
+ super(detailMessage);
+ }
+
+ /**
+ * Constructs a new {@code TransactionAbortError} with detail message and cause
+ * filled in.
+ *
+ * @param message the detail message for the exception.
+ * @param cause the detail cause for the exception.
+ */
+ private TransactionAbortError(String message, Throwable cause) {
+ super(message);
+ initCause(cause);
+ }
+
+ /**
+ * Constructs a new {@code TransactionAbortError} with its detail cause filled in.
+ *
+ * @param cause the detail cause for the exception.
+ */
+ private TransactionAbortError(Throwable cause) {
+ this(cause == null ? null : cause.toString(), cause);
+ }
+
+}
diff --git a/libart/src/main/java/dalvik/system/VMRuntime.java b/libart/src/main/java/dalvik/system/VMRuntime.java
index 43fa00e..aa3f154 100644
--- a/libart/src/main/java/dalvik/system/VMRuntime.java
+++ b/libart/src/main/java/dalvik/system/VMRuntime.java
@@ -16,6 +16,7 @@
package dalvik.system;
+import java.lang.ref.FinalizerReference;
import java.util.HashMap;
import java.util.Map;
@@ -33,6 +34,10 @@ public final class VMRuntime {
*/
private static final VMRuntime THE_ONE = new VMRuntime();
+ // Note: Instruction set names are used to construct the names of some
+ // system properties. To be sure that the properties stay valid the
+ // instruction set name should not exceed 7 characters. See installd
+ // and the package manager for the actual propeties.
private static final Map<String, String> ABI_TO_INSTRUCTION_SET_MAP
= new HashMap<String, String>();
static {
@@ -272,6 +277,12 @@ public final class VMRuntime {
public native void clearGrowthLimit();
/**
+ * Make the current growth limit the new non growth limit capacity by releasing pages which
+ * are after the growth limit but before the non growth limit capacity.
+ */
+ public native void clampGrowthLimit();
+
+ /**
* Returns true if either a Java debugger or native debugger is active.
*/
public native boolean isDebuggerActive();
@@ -291,8 +302,37 @@ public final class VMRuntime {
*/
public native void registerNativeFree(int bytes);
- public native void trimHeap();
+ /**
+ * Wait for objects to be finalized.
+ *
+ * If finalization takes longer than timeout, then the function returns before all objects are
+ * finalized.
+ *
+ * @param timeout
+ * timeout in nanoseconds of the maximum time to wait until all pending finalizers
+ * are run. If timeout is 0, then there is no timeout. Note that the timeout does
+ * not stop the finalization process, it merely stops the wait.
+ *
+ * @see #Runtime.runFinalization()
+ * @see #wait(long,int)
+ */
+ public static void runFinalization(long timeout) {
+ try {
+ FinalizerReference.finalizeAllEnqueued(timeout);
+ } catch (InterruptedException e) {
+ // Interrupt the current thread without actually throwing the InterruptionException
+ // for the caller.
+ Thread.currentThread().interrupt();
+ }
+ }
+
+ public native void requestConcurrentGC();
public native void concurrentGC();
+ public native void requestHeapTrim();
+ public native void trimHeap();
+ public native void startHeapTaskProcessor();
+ public native void stopHeapTaskProcessor();
+ public native void runHeapTasks();
/**
* Let the heap know of the new process state. This can change allocation and garbage collection
diff --git a/libart/src/main/java/dalvik/system/VMStack.java b/libart/src/main/java/dalvik/system/VMStack.java
index ee0a0db..b69ab60 100644
--- a/libart/src/main/java/dalvik/system/VMStack.java
+++ b/libart/src/main/java/dalvik/system/VMStack.java
@@ -48,11 +48,10 @@ public final class VMStack {
native public static Class<?> getStackClass2();
/**
- * Returns the first ClassLoader on the call stack that isn't either of
- * the passed-in ClassLoaders.
+ * Returns the first ClassLoader on the call stack that isn't the
+ * bootstrap class loader.
*/
- public native static ClassLoader getClosestUserClassLoader(ClassLoader bootstrap,
- ClassLoader system);
+ public native static ClassLoader getClosestUserClassLoader();
/**
* Retrieves the stack trace from the specified thread.
diff --git a/luni/src/main/java/java/lang/AbstractStringBuilder.java b/libart/src/main/java/java/lang/AbstractStringBuilder.java
index 4d84078..c8c8c5a 100644
--- a/luni/src/main/java/java/lang/AbstractStringBuilder.java
+++ b/libart/src/main/java/java/lang/AbstractStringBuilder.java
@@ -87,7 +87,7 @@ abstract class AbstractStringBuilder {
count = string.length();
shared = false;
value = new char[count + INITIAL_CAPACITY];
- string._getChars(0, count, value, 0);
+ string.getCharsNoCheck(0, count, value, 0);
}
private void enlargeBuffer(int min) {
@@ -145,7 +145,7 @@ abstract class AbstractStringBuilder {
if (newCount > value.length) {
enlargeBuffer(newCount);
}
- string._getChars(0, length, value, count);
+ string.getCharsNoCheck(0, length, value, count);
count = newCount;
}
@@ -167,7 +167,7 @@ abstract class AbstractStringBuilder {
}
if (s instanceof String) {
- ((String) s)._getChars(start, end, value, count);
+ ((String) s).getCharsNoCheck(start, end, value, count);
} else if (s instanceof AbstractStringBuilder) {
AbstractStringBuilder other = (AbstractStringBuilder) s;
System.arraycopy(other.value, start, value, count, length);
@@ -345,7 +345,7 @@ abstract class AbstractStringBuilder {
int min = string.length();
if (min != 0) {
move(min, index);
- string._getChars(0, min, value, index);
+ string.getCharsNoCheck(0, min, value, index);
count += min;
}
} else {
@@ -422,7 +422,7 @@ abstract class AbstractStringBuilder {
value = value.clone();
shared = false;
}
- string._getChars(0, stringLength, value, start);
+ string.getCharsNoCheck(0, stringLength, value, start);
count -= diff;
return;
}
@@ -626,14 +626,7 @@ abstract class AbstractStringBuilder {
if (count == 0) {
return "";
}
- // Optimize String sharing for more performance
- int wasted = value.length - count;
- if (wasted >= 256
- || (wasted >= INITIAL_CAPACITY && wasted >= (count >> 1))) {
- return new String(value, 0, count);
- }
- shared = true;
- return new String(0, count, value);
+ return StringFactory.newStringFromChars(0, count, value);
}
/**
diff --git a/luni/src/main/java/java/lang/CaseMapper.java b/libart/src/main/java/java/lang/CaseMapper.java
index 1da621c..f23a4ef 100644
--- a/luni/src/main/java/java/lang/CaseMapper.java
+++ b/libart/src/main/java/java/lang/CaseMapper.java
@@ -34,17 +34,15 @@ class CaseMapper {
/**
* Our current GC makes short-lived objects more expensive than we'd like. When that's fixed,
* this class should be changed so that you instantiate it with the String and its value,
- * offset, and count fields.
+ * and count fields.
*/
private CaseMapper() {
}
/**
- * Implements String.toLowerCase. We need 's' so that we can return the original String instance
- * if nothing changes. We need 'value', 'offset', and 'count' because they're not otherwise
- * accessible.
+ * Implements String.toLowerCase. The original String instance is returned if nothing changes.
*/
- public static String toLowerCase(Locale locale, String s, char[] value, int offset, int count) {
+ public static String toLowerCase(Locale locale, String s) {
// Punt hard cases to ICU4C.
// Note that Greek isn't a particularly hard case for toLowerCase, only toUpperCase.
String languageCode = locale.getLanguage();
@@ -52,29 +50,26 @@ class CaseMapper {
return ICU.toLowerCase(s, locale);
}
- char[] newValue = null;
- int newCount = 0;
- for (int i = offset, end = offset + count; i < end; ++i) {
- char ch = value[i];
+ String newString = null;
+ for (int i = 0, end = s.length(); i < end; ++i) {
+ char ch = s.charAt(i);
char newCh;
if (ch == LATIN_CAPITAL_I_WITH_DOT || Character.isHighSurrogate(ch)) {
// Punt these hard cases.
return ICU.toLowerCase(s, locale);
- } else if (ch == GREEK_CAPITAL_SIGMA && isFinalSigma(value, offset, count, i)) {
+ } else if (ch == GREEK_CAPITAL_SIGMA && isFinalSigma(s, i)) {
newCh = GREEK_SMALL_FINAL_SIGMA;
} else {
newCh = Character.toLowerCase(ch);
}
- if (newValue == null && ch != newCh) {
- newValue = new char[count]; // The result can't be longer than the input.
- newCount = i - offset;
- System.arraycopy(value, offset, newValue, 0, newCount);
- }
- if (newValue != null) {
- newValue[newCount++] = newCh;
+ if (ch != newCh) {
+ if (newString == null) {
+ newString = StringFactory.newStringFromString(s);
+ }
+ newString.setCharAt(i, newCh);
}
}
- return newValue != null ? new String(0, newCount, newValue) : s;
+ return newString != null ? newString : s;
}
/**
@@ -82,20 +77,20 @@ class CaseMapper {
* sequence, and 'index' is not followed by a sequence consisting of an ignorable sequence and
* then a cased letter.
*/
- private static boolean isFinalSigma(char[] value, int offset, int count, int index) {
+ private static boolean isFinalSigma(String s, int index) {
// TODO: we don't skip case-ignorable sequences like we should.
// TODO: we should add a more direct way to test for a cased letter.
- if (index <= offset) {
+ if (index <= 0) {
return false;
}
- char previous = value[index - 1];
+ char previous = s.charAt(index - 1);
if (!(Character.isLowerCase(previous) || Character.isUpperCase(previous) || Character.isTitleCase(previous))) {
return false;
}
- if (index + 1 >= offset + count) {
+ if (index + 1 >= s.length()) {
return true;
}
- char next = value[index + 1];
+ char next = s.charAt(index + 1);
if (Character.isLowerCase(next) || Character.isUpperCase(next) || Character.isTitleCase(next)) {
return false;
}
@@ -147,7 +142,7 @@ class CaseMapper {
}
};
- public static String toUpperCase(Locale locale, String s, char[] value, int offset, int count) {
+ public static String toUpperCase(Locale locale, String s, int count) {
String languageCode = locale.getLanguage();
if (languageCode.equals("tr") || languageCode.equals("az") || languageCode.equals("lt")) {
return ICU.toUpperCase(s, locale);
@@ -157,9 +152,10 @@ class CaseMapper {
}
char[] output = null;
+ String newString = null;
int i = 0;
- for (int o = offset, end = offset + count; o < end; o++) {
- char ch = value[o];
+ for (int o = 0, end = count; o < end; o++) {
+ char ch = s.charAt(o);
if (Character.isHighSurrogate(ch)) {
return ICU.toUpperCase(s, locale);
}
@@ -171,23 +167,25 @@ class CaseMapper {
output = newoutput;
}
char upch = Character.toUpperCase(ch);
- if (ch != upch) {
- if (output == null) {
- output = new char[count];
- i = o - offset;
- System.arraycopy(value, offset, output, 0, i);
- }
+ if (output != null) {
output[i++] = upch;
- } else if (output != null) {
- output[i++] = ch;
+ } else if (ch != upch) {
+ if (newString == null) {
+ newString = StringFactory.newStringFromString(s);
+ }
+ newString.setCharAt(o, upch);
}
} else {
int target = index * 3;
char val3 = upperValues[target + 2];
if (output == null) {
output = new char[count + (count / 6) + 2];
- i = o - offset;
- System.arraycopy(value, offset, output, 0, i);
+ i = o;
+ if (newString != null) {
+ System.arraycopy(newString.toCharArray(), 0, output, 0, i);
+ } else {
+ System.arraycopy(s.toCharArray(), 0, output, 0, i);
+ }
} else if (i + (val3 == 0 ? 1 : 2) >= output.length) {
char[] newoutput = new char[output.length + (count / 6) + 3];
System.arraycopy(output, 0, newoutput, 0, output.length);
@@ -204,7 +202,11 @@ class CaseMapper {
}
}
if (output == null) {
- return s;
+ if (newString != null) {
+ return newString;
+ } else {
+ return s;
+ }
}
return output.length == i || output.length - i < 8 ? new String(0, i, output) : new String(output, 0, i);
}
diff --git a/libart/src/main/java/java/lang/Class.java b/libart/src/main/java/java/lang/Class.java
index 8833776..fc6a0f8 100644
--- a/libart/src/main/java/java/lang/Class.java
+++ b/libart/src/main/java/java/lang/Class.java
@@ -39,8 +39,6 @@ import java.io.Serializable;
import java.lang.annotation.Annotation;
import java.lang.reflect.AccessibleObject;
import java.lang.reflect.AnnotatedElement;
-import java.lang.reflect.ArtField;
-import java.lang.reflect.ArtMethod;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.GenericDeclaration;
@@ -55,6 +53,7 @@ import java.nio.charset.StandardCharsets;
import java.security.ProtectionDomain;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Collections;
import java.util.List;
import libcore.reflect.AnnotationAccess;
import libcore.reflect.GenericSignatureParser;
@@ -124,16 +123,16 @@ public final class Class<T> implements Serializable, AnnotatedElement, GenericDe
private static final long serialVersionUID = 3206093459760846163L;
- /** defining class loader, or NULL for the "bootstrap" system loader. */
+ /** defining class loader, or null for the "bootstrap" system loader. */
private transient ClassLoader classLoader;
/**
* For array classes, the component class object for instanceof/checkcast (for String[][][],
- * this will be String[][]). NULL for non-array classes.
+ * this will be String[][]). null for non-array classes.
*/
private transient Class<?> componentType;
/**
- * DexCache of resolved constant pool entries. Will be null for certain VM-generated classes
+ * DexCache of resolved constant pool entries. Will be null for certain runtime-generated classes
* e.g. arrays and primitive classes.
*/
private transient DexCache dexCache;
@@ -141,19 +140,6 @@ public final class Class<T> implements Serializable, AnnotatedElement, GenericDe
/** Short-cut to dexCache.strings */
private transient String[] dexCacheStrings;
- /** static, private, and &lt;init&gt; methods. */
- private transient ArtMethod[] directMethods;
-
- /**
- * Instance fields. These describe the layout of the contents of an Object. Note that only the
- * fields directly declared by this class are listed in iFields; fields declared by a
- * superclass are listed in the superclass's Class.iFields.
- *
- * All instance fields that refer to objects are guaranteed to be at the beginning of the field
- * list. {@link Class#numReferenceInstanceFields} specifies the number of reference fields.
- */
- private transient ArtField[] iFields;
-
/**
* The interface table (iftable_) contains pairs of a interface class and an array of the
* interface methods. There is one pair per interface supported by this class. That
@@ -173,29 +159,42 @@ public final class Class<T> implements Serializable, AnnotatedElement, GenericDe
/** Lazily computed name of this class; always prefer calling getName(). */
private transient String name;
- /** Static fields */
- private transient ArtField[] sFields;
-
- /** The superclass, or NULL if this is java.lang.Object, an interface or primitive type. */
+ /** The superclass, or null if this is java.lang.Object, an interface or primitive type. */
private transient Class<? super T> superClass;
/** If class verify fails, we must return same error on subsequent tries. */
private transient Class<?> verifyErrorClass;
- /** Virtual methods defined in this class; invoked through vtable. */
- private transient ArtMethod[] virtualMethods;
-
/**
* Virtual method table (vtable), for use by "invoke-virtual". The vtable from the superclass
* is copied in, and virtual methods from our class either replace those from the super or are
* appended. For abstract classes, methods may be created in the vtable that aren't in
* virtual_ methods_ for miranda methods.
*/
- private transient ArtMethod[] vtable;
+ private transient Object vtable;
/** access flags; low 16 bits are defined by VM spec */
private transient int accessFlags;
+ /** static, private, and &lt;init&gt; methods. */
+ private transient long directMethods;
+
+ /**
+ * Instance fields. These describe the layout of the contents of an Object. Note that only the
+ * fields directly declared by this class are listed in iFields; fields declared by a
+ * superclass are listed in the superclass's Class.iFields.
+ *
+ * All instance fields that refer to objects are guaranteed to be at the beginning of the field
+ * list. {@link Class#numReferenceInstanceFields} specifies the number of reference fields.
+ */
+ private transient long iFields;
+
+ /** Static fields */
+ private transient long sFields;
+
+ /** Virtual methods defined in this class; invoked through vtable. */
+ private transient long virtualMethods;
+
/**
* Total size of the Class instance; used when allocating storage on GC heap.
* See also {@link Class#objectSize}.
@@ -221,32 +220,45 @@ public final class Class<T> implements Serializable, AnnotatedElement, GenericDe
*/
private transient volatile int dexTypeIndex;
+ /** Number of direct methods. */
+ private transient int numDirectMethods;
+
+ /** Number of instance fields. */
+ private transient int numInstanceFields;
+
/** Number of instance fields that are object references. */
private transient int numReferenceInstanceFields;
/** Number of static fields that are object references. */
private transient int numReferenceStaticFields;
+ /** Number of static fields. */
+ private transient int numStaticFields;
+
+ /** Number of virtual methods. */
+ private transient int numVirtualMethods;
+
/**
* Total object size; used when allocating storage on GC heap. For interfaces and abstract
* classes this will be zero. See also {@link Class#classSize}.
*/
private transient int objectSize;
- /** Primitive type value, or 0 if not a primitive type; set for generated primitive classes. */
+ /**
+ * The lower 16 bits is the primitive type value, or 0 if not a primitive type; set for
+ * generated primitive classes.
+ */
private transient int primitiveType;
/** Bitmap of offsets of iFields. */
private transient int referenceInstanceOffsets;
- /** Bitmap of offsets of sFields. */
- private transient int referenceStaticOffsets;
-
/** State of class initialization */
private transient int status;
private Class() {
- // Prevent this class to be instantiated, instance should be created by JVM only
+ // Prevent this class from being instantiated,
+ // instances should be created by the runtime only.
}
/**
@@ -284,6 +296,9 @@ public final class Class<T> implements Serializable, AnnotatedElement, GenericDe
* If the class has not yet been initialized and {@code shouldInitialize} is true,
* the class will be initialized.
*
+ * <p>If the provided {@code classLoader} is {@code null}, the bootstrap
+ * class loader will be used to load the class.
+ *
* @throws ClassNotFoundException
* if the requested class cannot be found.
* @throws LinkageError
@@ -296,7 +311,7 @@ public final class Class<T> implements Serializable, AnnotatedElement, GenericDe
ClassLoader classLoader) throws ClassNotFoundException {
if (classLoader == null) {
- classLoader = ClassLoader.getSystemClassLoader();
+ classLoader = BootClassLoader.getInstance();
}
// Catch an Exception thrown by the underlying native code. It wraps
// up everything inside a ClassNotFoundException, even if e.g. an
@@ -407,24 +422,7 @@ public final class Class<T> implements Serializable, AnnotatedElement, GenericDe
return null;
}
- ClassLoader loader = getClassLoaderImpl();
- if (loader == null) {
- loader = BootClassLoader.getInstance();
- }
- return loader;
- }
-
- /**
- * This must be provided by the VM vendor, as it is used by other provided
- * class implementations in this package. Outside of this class, it is used
- * by SecurityManager.classLoaderDepth(),
- * currentClassLoader() and currentLoadedClass(). Return the ClassLoader for
- * this Class without doing any security checks. The bootstrap ClassLoader
- * is returned, unlike getClassLoader() which returns null in place of the
- * bootstrap ClassLoader.
- */
- ClassLoader getClassLoaderImpl() {
- ClassLoader loader = classLoader;
+ final ClassLoader loader = classLoader;
return loader == null ? BootClassLoader.getInstance() : loader;
}
@@ -456,10 +454,10 @@ public final class Class<T> implements Serializable, AnnotatedElement, GenericDe
* @hide
*/
public String getDexCacheString(Dex dex, int dexStringIndex) {
- String s = dexCacheStrings[dexStringIndex];
+ String s = dexCache.getResolvedString(dexStringIndex);
if (s == null) {
s = dex.strings().get(dexStringIndex).intern();
- dexCacheStrings[dexStringIndex] = s;
+ dexCache.setResolvedString(dexStringIndex, s);
}
return s;
}
@@ -471,13 +469,12 @@ public final class Class<T> implements Serializable, AnnotatedElement, GenericDe
* @hide
*/
public Class<?> getDexCacheType(Dex dex, int dexTypeIndex) {
- Class<?>[] dexCacheResolvedTypes = dexCache.resolvedTypes;
- Class<?> resolvedType = dexCacheResolvedTypes[dexTypeIndex];
+ Class<?> resolvedType = dexCache.getResolvedType(dexTypeIndex);
if (resolvedType == null) {
int descriptorIndex = dex.typeIds().get(dexTypeIndex);
String descriptor = getDexCacheString(dex, descriptorIndex);
resolvedType = InternalNames.getClass(getClassLoader(), descriptor);
- dexCacheResolvedTypes[dexTypeIndex] = resolvedType;
+ dexCache.setResolvedType(dexTypeIndex, resolvedType);
}
return resolvedType;
}
@@ -534,30 +531,12 @@ public final class Class<T> implements Serializable, AnnotatedElement, GenericDe
}
/**
- * Returns the constructor with the given parameters if it is defined by this class; null
- * otherwise. This may return a non-public member.
+ * Returns the constructor with the given parameters if it is defined by this class;
+ * {@code null} otherwise. This may return a non-public member.
*
* @param args the types of the parameters to the constructor.
*/
- private Constructor<T> getDeclaredConstructorInternal(Class<?>[] args) {
- if (directMethods != null) {
- for (ArtMethod m : directMethods) {
- int modifiers = m.getAccessFlags();
- if (Modifier.isStatic(modifiers)) {
- // skip <clinit> which is a static constructor
- continue;
- }
- if (!Modifier.isConstructor(modifiers)) {
- continue;
- }
- if (!ArtMethod.equalConstructorParameters(m, args)) {
- continue;
- }
- return new Constructor<T>(m);
- }
- }
- return null;
- }
+ private native Constructor<T> getDeclaredConstructorInternal(Class<?>[] args);
/**
* Returns an array containing {@code Constructor} objects for all public
@@ -568,9 +547,7 @@ public final class Class<T> implements Serializable, AnnotatedElement, GenericDe
* @see #getDeclaredConstructors()
*/
public Constructor<?>[] getConstructors() {
- ArrayList<Constructor<T>> constructors = new ArrayList();
- getDeclaredConstructors(true, constructors);
- return constructors.toArray(new Constructor[constructors.size()]);
+ return getDeclaredConstructorsInternal(true);
}
/**
@@ -582,28 +559,11 @@ public final class Class<T> implements Serializable, AnnotatedElement, GenericDe
* @see #getConstructors()
*/
public Constructor<?>[] getDeclaredConstructors() {
- ArrayList<Constructor<T>> constructors = new ArrayList();
- getDeclaredConstructors(false, constructors);
- return constructors.toArray(new Constructor[constructors.size()]);
- }
-
- private void getDeclaredConstructors(boolean publicOnly, List<Constructor<T>> constructors) {
- if (directMethods != null) {
- for (ArtMethod m : directMethods) {
- int modifiers = m.getAccessFlags();
- if (!publicOnly || Modifier.isPublic(modifiers)) {
- if (Modifier.isStatic(modifiers)) {
- // skip <clinit> which is a static constructor
- continue;
- }
- if (Modifier.isConstructor(modifiers)) {
- constructors.add(new Constructor<T>(m));
- }
- }
- }
- }
+ return getDeclaredConstructorsInternal(false);
}
+ private native Constructor<?>[] getDeclaredConstructorsInternal(boolean publicOnly);
+
/**
* Returns a {@code Method} object which represents the method matching the
* specified name and parameter types that is declared by the class
@@ -689,68 +649,13 @@ public final class Class<T> implements Serializable, AnnotatedElement, GenericDe
}
/**
- * Returns the method if it is defined by this class; null otherwise. This may return a
+ * Returns the method if it is defined by this class; {@code null} otherwise. This may return a
* non-public member.
*
* @param name the method name
* @param args the method's parameter types
*/
- private Method getDeclaredMethodInternal(String name, Class<?>[] args) {
- // Covariant return types permit the class to define multiple
- // methods with the same name and parameter types. Prefer to
- // return a non-synthetic method in such situations. We may
- // still return a synthetic method to handle situations like
- // escalated visibility. We never return miranda methods that
- // were synthesized by the VM.
- int skipModifiers = Modifier.MIRANDA | Modifier.SYNTHETIC;
- ArtMethod artMethodResult = null;
- if (virtualMethods != null) {
- for (ArtMethod m : virtualMethods) {
- String methodName = ArtMethod.getMethodName(m);
- if (!name.equals(methodName)) {
- continue;
- }
- if (!ArtMethod.equalMethodParameters(m, args)) {
- continue;
- }
- int modifiers = m.getAccessFlags();
- if ((modifiers & skipModifiers) == 0) {
- return new Method(m);
- }
- if ((modifiers & Modifier.MIRANDA) == 0) {
- // Remember as potential result if it's not a miranda method.
- artMethodResult = m;
- }
- }
- }
- if (artMethodResult == null) {
- if (directMethods != null) {
- for (ArtMethod m : directMethods) {
- int modifiers = m.getAccessFlags();
- if (Modifier.isConstructor(modifiers)) {
- continue;
- }
- String methodName = ArtMethod.getMethodName(m);
- if (!name.equals(methodName)) {
- continue;
- }
- if (!ArtMethod.equalMethodParameters(m, args)) {
- continue;
- }
- if ((modifiers & skipModifiers) == 0) {
- return new Method(m);
- }
- // Direct methods cannot be miranda methods,
- // so this potential result must be synthetic.
- artMethodResult = m;
- }
- }
- }
- if (artMethodResult == null) {
- return null;
- }
- return new Method(artMethodResult);
- }
+ private native Method getDeclaredMethodInternal(String name, Class<?>[] args);
/**
* Returns an array containing {@code Method} objects for all methods
@@ -761,11 +666,7 @@ public final class Class<T> implements Serializable, AnnotatedElement, GenericDe
* @see #getMethods()
*/
public Method[] getDeclaredMethods() {
- int initial_size = virtualMethods == null ? 0 : virtualMethods.length;
- initial_size += directMethods == null ? 0 : directMethods.length;
- ArrayList<Method> methods = new ArrayList<Method>(initial_size);
- getDeclaredMethodsUnchecked(false, methods);
- Method[] result = methods.toArray(new Method[methods.size()]);
+ Method[] result = getDeclaredMethodsUnchecked(false);
for (Method m : result) {
// Throw NoClassDefFoundError if types cannot be resolved.
m.getReturnType();
@@ -783,30 +684,7 @@ public final class Class<T> implements Serializable, AnnotatedElement, GenericDe
* @param methods A list to populate with declared methods.
* @hide
*/
- public void getDeclaredMethodsUnchecked(boolean publicOnly, List<Method> methods) {
- if (virtualMethods != null) {
- for (ArtMethod m : virtualMethods) {
- int modifiers = m.getAccessFlags();
- if (!publicOnly || Modifier.isPublic(modifiers)) {
- // Add non-miranda virtual methods.
- if ((modifiers & Modifier.MIRANDA) == 0) {
- methods.add(new Method(m));
- }
- }
- }
- }
- if (directMethods != null) {
- for (ArtMethod m : directMethods) {
- int modifiers = m.getAccessFlags();
- if (!publicOnly || Modifier.isPublic(modifiers)) {
- // Add non-constructor direct/static methods.
- if (!Modifier.isConstructor(modifiers)) {
- methods.add(new Method(m));
- }
- }
- }
- }
- }
+ public native Method[] getDeclaredMethodsUnchecked(boolean publicOnly);
/**
* Returns an array containing {@code Method} objects for all public methods
@@ -836,11 +714,11 @@ public final class Class<T> implements Serializable, AnnotatedElement, GenericDe
* superclasses, and all implemented interfaces, including overridden methods.
*/
private void getPublicMethodsInternal(List<Method> result) {
- getDeclaredMethodsUnchecked(true, result);
+ Collections.addAll(result, getDeclaredMethodsUnchecked(true));
if (!isInterface()) {
// Search superclasses, for interfaces don't search java.lang.Object.
for (Class<?> c = superClass; c != null; c = c.superClass) {
- c.getDeclaredMethodsUnchecked(true, result);
+ Collections.addAll(result, c.getDeclaredMethodsUnchecked(true));
}
}
// Search iftable which has a flattened and uniqued list of interfaces.
@@ -848,7 +726,7 @@ public final class Class<T> implements Serializable, AnnotatedElement, GenericDe
if (iftable != null) {
for (int i = 0; i < iftable.length; i += 2) {
Class<?> ifc = (Class<?>) iftable[i];
- ifc.getDeclaredMethodsUnchecked(true, result);
+ Collections.addAll(result, ifc.getDeclaredMethodsUnchecked(true));
}
}
}
@@ -881,18 +759,7 @@ public final class Class<T> implements Serializable, AnnotatedElement, GenericDe
* @throws NoSuchFieldException if the requested field can not be found.
* @see #getField(String)
*/
- public Field getDeclaredField(String name) throws NoSuchFieldException {
- if (name == null) {
- throw new NullPointerException("name == null");
- }
- Field result = getDeclaredFieldInternal(name);
- if (result == null) {
- throw new NoSuchFieldException(name);
- } else {
- result.getType(); // Throw NoClassDefFoundError if type cannot be resolved.
- }
- return result;
- }
+ public native Field getDeclaredField(String name) throws NoSuchFieldException;
/**
* Returns an array containing {@code Field} objects for all fields declared
@@ -902,17 +769,7 @@ public final class Class<T> implements Serializable, AnnotatedElement, GenericDe
*
* @see #getFields()
*/
- public Field[] getDeclaredFields() {
- int initial_size = sFields == null ? 0 : sFields.length;
- initial_size += iFields == null ? 0 : iFields.length;
- ArrayList<Field> fields = new ArrayList(initial_size);
- getDeclaredFieldsUnchecked(false, fields);
- Field[] result = fields.toArray(new Field[fields.size()]);
- for (Field f : result) {
- f.getType(); // Throw NoClassDefFoundError if type cannot be resolved.
- }
- return result;
- }
+ public native Field[] getDeclaredFields();
/**
* Populates a list of fields without performing any security or type
@@ -922,66 +779,18 @@ public final class Class<T> implements Serializable, AnnotatedElement, GenericDe
* @param fields A list to populate with declared fields.
* @hide
*/
- public void getDeclaredFieldsUnchecked(boolean publicOnly, List<Field> fields) {
- if (iFields != null) {
- for (ArtField f : iFields) {
- if (!publicOnly || Modifier.isPublic(f.getAccessFlags())) {
- fields.add(new Field(f));
- }
- }
- }
- if (sFields != null) {
- for (ArtField f : sFields) {
- if (!publicOnly || Modifier.isPublic(f.getAccessFlags())) {
- fields.add(new Field(f));
- }
- }
- }
- }
+ public native Field[] getDeclaredFieldsUnchecked(boolean publicOnly);
/**
- * Returns the field if it is defined by this class; null otherwise. This
+ * Returns the field if it is defined by this class; {@code null} otherwise. This
* may return a non-public member.
*/
- private Field getDeclaredFieldInternal(String name) {
-
- if (iFields != null) {
- final ArtField matched = findByName(name, iFields);
- if (matched != null) {
- return new Field(matched);
- }
- }
- if (sFields != null) {
- final ArtField matched = findByName(name, sFields);
- if (matched != null) {
- return new Field(matched);
- }
- }
-
- return null;
- }
+ private native Field getDeclaredFieldInternal(String name);
/**
- * Performs a binary search through {@code fields} for a field whose name
- * is {@code name}. Returns {@code null} if no matching field exists.
+ * Returns the subset of getDeclaredFields which are public.
*/
- private static ArtField findByName(String name, ArtField[] fields) {
- int low = 0, high = fields.length - 1;
- while (low <= high) {
- final int mid = (low + high) >>> 1;
- final ArtField f = fields[mid];
- final int result = f.getName().compareTo(name);
- if (result < 0) {
- low = mid + 1;
- } else if (result == 0) {
- return f;
- } else {
- high = mid - 1;
- }
- }
-
- return null;
- }
+ private native Field[] getPublicDeclaredFields();
/**
* Returns the class that this class is a member of, or {@code null} if this
@@ -1080,8 +889,6 @@ public final class Class<T> implements Serializable, AnnotatedElement, GenericDe
Field result = getPublicFieldRecursive(name);
if (result == null) {
throw new NoSuchFieldException(name);
- } else {
- result.getType(); // Throw NoClassDefFoundError if type cannot be resolved.
}
return result;
}
@@ -1098,8 +905,7 @@ public final class Class<T> implements Serializable, AnnotatedElement, GenericDe
// search iftable which has a flattened and uniqued list of interfaces
if (ifTable != null) {
for (int i = 0; i < ifTable.length; i += 2) {
- Class<?> ifc = (Class<?>) ifTable[i];
- Field result = ifc.getPublicFieldRecursive(name);
+ Field result = ((Class<?>) ifTable[i]).getPublicFieldRecursive(name);
if (result != null && (result.getModifiers() & Modifier.PUBLIC) != 0) {
return result;
}
@@ -1123,11 +929,7 @@ public final class Class<T> implements Serializable, AnnotatedElement, GenericDe
public Field[] getFields() {
List<Field> fields = new ArrayList<Field>();
getPublicFieldsRecursive(fields);
- Field[] result = fields.toArray(new Field[fields.size()]);
- for (Field f : result) {
- f.getType(); // Throw NoClassDefFoundError if type cannot be resolved.
- }
- return result;
+ return fields.toArray(new Field[fields.size()]);
}
/**
@@ -1137,15 +939,14 @@ public final class Class<T> implements Serializable, AnnotatedElement, GenericDe
private void getPublicFieldsRecursive(List<Field> result) {
// search superclasses
for (Class<?> c = this; c != null; c = c.superClass) {
- c.getDeclaredFieldsUnchecked(true, result);
+ Collections.addAll(result, c.getPublicDeclaredFields());
}
// search iftable which has a flattened and uniqued list of interfaces
Object[] iftable = ifTable;
if (iftable != null) {
for (int i = 0; i < iftable.length; i += 2) {
- Class<?> ifc = (Class<?>) iftable[i];
- ifc.getDeclaredFieldsUnchecked(true, result);
+ Collections.addAll(result, ((Class<?>) iftable[i]).getPublicDeclaredFields());
}
}
}
@@ -1295,21 +1096,21 @@ public final class Class<T> implements Serializable, AnnotatedElement, GenericDe
}
/**
- * Returns the simple name of a member or local class, or null otherwise.
+ * Returns the simple name of a member or local class, or {@code null} otherwise.
*/
private String getInnerClassName() {
return AnnotationAccess.getInnerClassName(this);
}
/**
- * Returns null.
+ * Returns {@code null}.
*/
public ProtectionDomain getProtectionDomain() {
return null;
}
/**
- * Returns the URL of the given resource, or null if the resource is not found.
+ * Returns the URL of the given resource, or {@code null} if the resource is not found.
* The mapping between the resource name and the URL is managed by the class' class loader.
*
* @see ClassLoader
@@ -1340,8 +1141,8 @@ public final class Class<T> implements Serializable, AnnotatedElement, GenericDe
}
/**
- * Returns a read-only stream for the contents of the given resource, or null if the resource
- * is not found.
+ * Returns a read-only stream for the contents of the given resource, or {@code null} if the
+ * resource is not found.
* The mapping between the resource name and the stream is managed by the class' class loader.
*
* @see ClassLoader
@@ -1372,8 +1173,8 @@ public final class Class<T> implements Serializable, AnnotatedElement, GenericDe
}
/**
- * Returns null. (On Android, a {@code ClassLoader} can load classes from multiple dex files.
- * All classes from any given dex file will have the same signers, but different dex
+ * Returns {@code null}. (On Android, a {@code ClassLoader} can load classes from multiple dex
+ * files. All classes from any given dex file will have the same signers, but different dex
* files may have different signers. This does not fit well with the original
* {@code ClassLoader}-based model of {@code getSigners}.)
*/
@@ -1475,8 +1276,7 @@ public final class Class<T> implements Serializable, AnnotatedElement, GenericDe
Object[] iftable = c.ifTable;
if (iftable != null) {
for (int i = 0; i < iftable.length; i += 2) {
- Class<?> ifc = (Class<?>) iftable[i];
- if (ifc == this) {
+ if (iftable[i] == this) {
return true;
}
}
@@ -1547,7 +1347,7 @@ public final class Class<T> implements Serializable, AnnotatedElement, GenericDe
* Tests whether this {@code Class} represents a primitive type.
*/
public boolean isPrimitive() {
- return primitiveType != 0;
+ return (primitiveType & 0xFFFF) != 0;
}
/**
@@ -1582,33 +1382,7 @@ public final class Class<T> implements Serializable, AnnotatedElement, GenericDe
* @throws InstantiationException
* if the instance cannot be created.
*/
- public T newInstance() throws InstantiationException, IllegalAccessException {
- if (isPrimitive() || isInterface() || isArray() || Modifier.isAbstract(accessFlags)) {
- throw new InstantiationException(this + " cannot be instantiated");
- }
- Class<?> caller = VMStack.getStackClass1();
- if (!caller.canAccess(this)) {
- throw new IllegalAccessException(this + " is not accessible from " + caller);
- }
- Constructor<T> init;
- try {
- init = getDeclaredConstructor();
- } catch (NoSuchMethodException e) {
- InstantiationException t =
- new InstantiationException(this + " has no zero argument constructor");
- t.initCause(e);
- throw t;
- }
- if (!caller.canAccessMember(this, init.getAccessFlags())) {
- throw new IllegalAccessException(init + " is not accessible from " + caller);
- }
- try {
- return init.newInstance(null, init.isAccessible());
- } catch (InvocationTargetException e) {
- SneakyThrow.sneakyThrow(e.getCause());
- return null; // Unreachable.
- }
- }
+ public native T newInstance() throws InstantiationException, IllegalAccessException;
private boolean canAccess(Class<?> c) {
if(Modifier.isPublic(c.accessFlags)) {
@@ -1664,7 +1438,7 @@ public final class Class<T> implements Serializable, AnnotatedElement, GenericDe
* object was created by the class loader of the class.
*/
public Package getPackage() {
- // TODO This might be a hack, but the VM doesn't have the necessary info.
+ // TODO This might be a hack, but the runtime doesn't have the necessary info.
ClassLoader loader = getClassLoader();
if (loader != null) {
String packageName = getPackageName$();
@@ -1674,7 +1448,7 @@ public final class Class<T> implements Serializable, AnnotatedElement, GenericDe
}
/**
- * Returns the package name of this class. This returns null for classes in
+ * Returns the package name of this class. This returns {@code null} for classes in
* the default package.
*
* @hide
diff --git a/libart/src/main/java/java/lang/ClassLoader.java b/libart/src/main/java/java/lang/ClassLoader.java
index 9079dc4..dfbeeb5 100644
--- a/libart/src/main/java/java/lang/ClassLoader.java
+++ b/libart/src/main/java/java/lang/ClassLoader.java
@@ -646,8 +646,8 @@ public abstract class ClassLoader {
throw new IllegalArgumentException("Package " + name + " already defined");
}
- Package newPackage = new Package(name, specTitle, specVersion, specVendor, implTitle,
- implVersion, implVendor, sealBase);
+ Package newPackage = new Package(this, name, specTitle, specVersion, specVendor,
+ implTitle, implVersion, implVendor, sealBase);
packages.put(name, newPackage);
diff --git a/libart/src/main/java/java/lang/Daemons.java b/libart/src/main/java/java/lang/Daemons.java
index 485f2c9..a6ac449 100644
--- a/libart/src/main/java/java/lang/Daemons.java
+++ b/libart/src/main/java/java/lang/Daemons.java
@@ -16,6 +16,8 @@
package java.lang;
+import android.system.Os;
+import android.system.OsConstants;
import dalvik.system.VMRuntime;
import java.lang.ref.FinalizerReference;
import java.lang.ref.Reference;
@@ -40,16 +42,14 @@ public final class Daemons {
ReferenceQueueDaemon.INSTANCE.start();
FinalizerDaemon.INSTANCE.start();
FinalizerWatchdogDaemon.INSTANCE.start();
- HeapTrimmerDaemon.INSTANCE.start();
- GCDaemon.INSTANCE.start();
+ HeapTaskDaemon.INSTANCE.start();
}
public static void stop() {
+ HeapTaskDaemon.INSTANCE.stop();
ReferenceQueueDaemon.INSTANCE.stop();
FinalizerDaemon.INSTANCE.stop();
FinalizerWatchdogDaemon.INSTANCE.stop();
- HeapTrimmerDaemon.INSTANCE.stop();
- GCDaemon.INSTANCE.stop();
}
/**
@@ -59,12 +59,17 @@ public final class Daemons {
*/
private static abstract class Daemon implements Runnable {
private Thread thread;
+ private String name;
+
+ protected Daemon(String name) {
+ this.name = name;
+ }
public synchronized void start() {
if (thread != null) {
throw new IllegalStateException("already running");
}
- thread = new Thread(ThreadGroup.systemThreadGroup, this, getClass().getSimpleName());
+ thread = new Thread(ThreadGroup.systemThreadGroup, this, name);
thread.setDaemon(true);
thread.start();
}
@@ -80,6 +85,10 @@ public final class Daemons {
}
public synchronized void interrupt() {
+ interrupt(thread);
+ }
+
+ public synchronized void interrupt(Thread thread) {
if (thread == null) {
throw new IllegalStateException("not running");
}
@@ -99,7 +108,7 @@ public final class Daemons {
if (threadToStop == null) {
throw new IllegalStateException("not running");
}
- threadToStop.interrupt();
+ interrupt(threadToStop);
while (true) {
try {
threadToStop.join();
@@ -125,6 +134,10 @@ public final class Daemons {
private static class ReferenceQueueDaemon extends Daemon {
private static final ReferenceQueueDaemon INSTANCE = new ReferenceQueueDaemon();
+ ReferenceQueueDaemon() {
+ super("ReferenceQueueDaemon");
+ }
+
@Override public void run() {
while (isRunning()) {
Reference<?> list;
@@ -144,20 +157,14 @@ public final class Daemons {
}
private void enqueue(Reference<?> list) {
- while (list != null) {
- Reference<?> reference;
- // pendingNext is owned by the GC so no synchronization is required
- if (list == list.pendingNext) {
- reference = list;
- reference.pendingNext = null;
- list = null;
- } else {
- reference = list.pendingNext;
- list.pendingNext = reference.pendingNext;
- reference.pendingNext = null;
- }
- reference.enqueueInternal();
- }
+ Reference<?> start = list;
+ do {
+ // pendingNext is owned by the GC so no synchronization is required.
+ Reference<?> next = list.pendingNext;
+ list.pendingNext = null;
+ list.enqueueInternal();
+ list = next;
+ } while (list != start);
}
}
@@ -167,6 +174,10 @@ public final class Daemons {
private volatile Object finalizingObject;
private volatile long finalizingStartedNanos;
+ FinalizerDaemon() {
+ super("FinalizerDaemon");
+ }
+
@Override public void run() {
while (isRunning()) {
// Take a reference, blocking until one is ready or the thread should stop
@@ -207,6 +218,10 @@ public final class Daemons {
private static class FinalizerWatchdogDaemon extends Daemon {
private static final FinalizerWatchdogDaemon INSTANCE = new FinalizerWatchdogDaemon();
+ FinalizerWatchdogDaemon() {
+ super("FinalizerWatchdogDaemon");
+ }
+
@Override public void run() {
while (isRunning()) {
boolean waitSuccessful = waitForObject();
@@ -282,6 +297,14 @@ public final class Daemons {
// We use the stack from where finalize() was running to show where it was stuck.
syntheticException.setStackTrace(FinalizerDaemon.INSTANCE.getStackTrace());
Thread.UncaughtExceptionHandler h = Thread.getDefaultUncaughtExceptionHandler();
+ // Send SIGQUIT to get native stack traces.
+ try {
+ Os.kill(Os.getpid(), OsConstants.SIGQUIT);
+ // Sleep a few seconds to let the stack traces print.
+ Thread.sleep(5000);
+ } catch (Exception e) {
+ System.logE("failed to send SIGQUIT", e);
+ }
if (h == null) {
// If we have no handler, log and exit.
System.logE(message, syntheticException);
@@ -294,59 +317,42 @@ public final class Daemons {
}
}
- // Invoked by the GC to request that the HeapTrimmerDaemon thread attempt to trim the heap.
+ // Adds a heap trim task ot the heap event processor, not called from java. Left for
+ // compatibility purposes due to reflection.
public static void requestHeapTrim() {
- synchronized (HeapTrimmerDaemon.INSTANCE) {
- HeapTrimmerDaemon.INSTANCE.notify();
- }
- }
-
- private static class HeapTrimmerDaemon extends Daemon {
- private static final HeapTrimmerDaemon INSTANCE = new HeapTrimmerDaemon();
-
- @Override public void run() {
- while (isRunning()) {
- try {
- synchronized (this) {
- wait();
- }
- VMRuntime.getRuntime().trimHeap();
- } catch (InterruptedException ignored) {
- }
- }
- }
+ VMRuntime.getRuntime().requestHeapTrim();
}
- // Invoked by the GC to request that the HeapTrimmerDaemon thread attempt to trim the heap.
+ // Adds a concurrent GC request task ot the heap event processor, not called from java. Left
+ // for compatibility purposes due to reflection.
public static void requestGC() {
- GCDaemon.INSTANCE.requestGC();
+ VMRuntime.getRuntime().requestConcurrentGC();
}
- private static class GCDaemon extends Daemon {
- private static final GCDaemon INSTANCE = new GCDaemon();
- private static final AtomicBoolean atomicBoolean = new AtomicBoolean();
+ private static class HeapTaskDaemon extends Daemon {
+ private static final HeapTaskDaemon INSTANCE = new HeapTaskDaemon();
- public void requestGC() {
- if (atomicBoolean.getAndSet(true)) {
- return;
- }
- synchronized (this) {
- notify();
- }
- atomicBoolean.set(false);
+ HeapTaskDaemon() {
+ super("HeapTaskDaemon");
+ }
+
+ // Overrides the Daemon.interupt method which is called from Daemons.stop.
+ public synchronized void interrupt(Thread thread) {
+ VMRuntime.getRuntime().stopHeapTaskProcessor();
}
@Override public void run() {
- while (isRunning()) {
- try {
- synchronized (this) {
- // Wait until a request comes in.
- wait();
- }
- VMRuntime.getRuntime().concurrentGC();
- } catch (InterruptedException ignored) {
+ synchronized (this) {
+ if (isRunning()) {
+ // Needs to be synchronized or else we there is a race condition where we start
+ // the thread, call stopHeapTaskProcessor before we start the heap task
+ // processor, resulting in a deadlock since startHeapTaskProcessor restarts it
+ // while the other thread is waiting in Daemons.stop().
+ VMRuntime.getRuntime().startHeapTaskProcessor();
}
}
+ // This runs tasks until we are stopped and there is no more pending task.
+ VMRuntime.getRuntime().runHeapTasks();
}
}
}
diff --git a/libart/src/main/java/java/lang/DexCache.java b/libart/src/main/java/java/lang/DexCache.java
index e4caffa..73e35cd 100644
--- a/libart/src/main/java/java/lang/DexCache.java
+++ b/libart/src/main/java/java/lang/DexCache.java
@@ -33,8 +33,6 @@
package java.lang;
import com.android.dex.Dex;
-import java.lang.reflect.ArtField;
-import java.lang.reflect.ArtMethod;
/**
* A dex cache holds resolved copies of strings, fields, methods, and classes from the dexfile.
@@ -47,16 +45,16 @@ final class DexCache {
String location;
/**
- * References to fields as they become resolved following interpreter semantics. May refer to
- * fields defined in other dex files.
+ * References to methods as they become resolved following interpreter semantics. May refer to
+ * methods defined in other dex files.
*/
- ArtField[] resolvedFields;
+ Object resolvedMethods;
/**
- * References to methods as they become resolved following interpreter semantics. May refer to
- * methods defined in other dex files.
+ * References to fields as they become resolved following interpreter semantics. May refer to
+ * fields defined in other dex files. Either an int array or long array.
*/
- ArtMethod[] resolvedMethods;
+ private Object resolvedFields;
/**
* References to types as they become resolved following interpreter semantics. May refer to
@@ -89,6 +87,10 @@ final class DexCache {
return result;
}
+ native Class<?> getResolvedType(int typeIndex);
+ native String getResolvedString(int stringIndex);
+ native void setResolvedType(int typeIndex, Class<?> type);
+ native void setResolvedString(int stringIndex, String string);
private native Dex getDexNative();
}
diff --git a/libart/src/main/java/java/lang/Object.java b/libart/src/main/java/java/lang/Object.java
index 20fdbf9..5b820e3 100644
--- a/libart/src/main/java/java/lang/Object.java
+++ b/libart/src/main/java/java/lang/Object.java
@@ -274,10 +274,11 @@ public class Object {
*/
public int hashCode() {
int lockWord = shadow$_monitor_;
- final int lockWordMask = 0xC0000000; // Top 2 bits.
+ final int lockWordStateMask = 0xC0000000; // Top 2 bits.
final int lockWordStateHash = 0x80000000; // Top 2 bits are value 2 (kStateHash).
- if ((lockWord & lockWordMask) == lockWordStateHash) {
- return lockWord & ~lockWordMask;
+ final int lockWordHashMask = 0x0FFFFFFF; // Low 28 bits.
+ if ((lockWord & lockWordStateMask) == lockWordStateHash) {
+ return lockWord & lockWordHashMask;
}
return System.identityHashCode(this);
}
diff --git a/libart/src/main/java/java/lang/String.java b/libart/src/main/java/java/lang/String.java
index 0107b6e..0875d1a 100644
--- a/libart/src/main/java/java/lang/String.java
+++ b/libart/src/main/java/java/lang/String.java
@@ -22,12 +22,12 @@ import java.io.UnsupportedEncodingException;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.charset.Charset;
-import java.nio.charset.Charsets;
import java.util.Arrays;
import java.util.Comparator;
import java.util.Formatter;
import java.util.Locale;
import java.util.regex.Pattern;
+import libcore.util.CharsetUtils;
import libcore.util.EmptyArray;
/**
@@ -35,23 +35,6 @@ import libcore.util.EmptyArray;
* See {@link Character} for details about the relationship between {@code char} and
* Unicode code points.
*
- * <a name="backing_array"><h3>Backing Arrays</h3></a>
- * This class is implemented using a {@code char[]}. The length of the array may exceed
- * the length of the string. For example, the string "Hello" may be backed by
- * the array {@code ['H', 'e', 'l', 'l', 'o', 'W'. 'o', 'r', 'l', 'd']} with
- * offset 0 and length 5.
- *
- * <p>Multiple strings can share the same {@code char[]} because strings are immutable.
- * The {@link #substring} method <strong>always</strong> returns a string that
- * shares the backing array of its source string. Generally this is an
- * optimization: fewer {@code char[]}s need to be allocated, and less copying
- * is necessary. But this can also lead to unwanted heap retention. Taking a
- * short substring of long string means that the long shared {@code char[]} won't be
- * garbage until both strings are garbage. This typically happens when parsing
- * small substrings out of a large input. To avoid this where necessary, call
- * {@code new String(longString.subString(...))}. The string copy constructor
- * always ensures that the backing array is no larger than necessary.
- *
* @see StringBuffer
* @see StringBuilder
* @see Charset
@@ -93,10 +76,6 @@ public final class String implements Serializable, Comparable<String>, CharSeque
}
}
- private final char[] value;
-
- private final int offset;
-
private final int count;
private int hashCode;
@@ -105,9 +84,7 @@ public final class String implements Serializable, Comparable<String>, CharSeque
* Creates an empty string.
*/
public String() {
- value = EmptyArray.CHAR;
- offset = 0;
- count = 0;
+ throw new UnsupportedOperationException("Use StringFactory instead.");
}
/**
@@ -116,7 +93,7 @@ public final class String implements Serializable, Comparable<String>, CharSeque
*/
@FindBugsSuppressWarnings("DM_DEFAULT_ENCODING")
public String(byte[] data) {
- this(data, 0, data.length);
+ throw new UnsupportedOperationException("Use StringFactory instead.");
}
/**
@@ -133,7 +110,7 @@ public final class String implements Serializable, Comparable<String>, CharSeque
*/
@Deprecated
public String(byte[] data, int high) {
- this(data, high, 0, data.length);
+ throw new UnsupportedOperationException("Use StringFactory instead.");
}
/**
@@ -146,7 +123,7 @@ public final class String implements Serializable, Comparable<String>, CharSeque
* if {@code byteCount < 0 || offset < 0 || offset + byteCount > data.length}.
*/
public String(byte[] data, int offset, int byteCount) {
- this(data, offset, byteCount, Charset.defaultCharset());
+ throw new UnsupportedOperationException("Use StringFactory instead.");
}
/**
@@ -162,16 +139,7 @@ public final class String implements Serializable, Comparable<String>, CharSeque
*/
@Deprecated
public String(byte[] data, int high, int offset, int byteCount) {
- if ((offset | byteCount) < 0 || byteCount > data.length - offset) {
- throw failedBoundsCheck(data.length, offset, byteCount);
- }
- this.offset = 0;
- this.value = new char[byteCount];
- this.count = byteCount;
- high <<= 8;
- for (int i = 0; i < count; i++) {
- value[i] = (char) (high + (data[offset++] & 0xff));
- }
+ throw new UnsupportedOperationException("Use StringFactory instead.");
}
/**
@@ -188,7 +156,7 @@ public final class String implements Serializable, Comparable<String>, CharSeque
* if the named charset is not supported.
*/
public String(byte[] data, int offset, int byteCount, String charsetName) throws UnsupportedEncodingException {
- this(data, offset, byteCount, Charset.forNameUEE(charsetName));
+ throw new UnsupportedOperationException("Use StringFactory instead.");
}
/**
@@ -203,7 +171,7 @@ public final class String implements Serializable, Comparable<String>, CharSeque
* if {@code charsetName} is not supported.
*/
public String(byte[] data, String charsetName) throws UnsupportedEncodingException {
- this(data, 0, data.length, Charset.forNameUEE(charsetName));
+ throw new UnsupportedOperationException("Use StringFactory instead.");
}
/**
@@ -221,144 +189,7 @@ public final class String implements Serializable, Comparable<String>, CharSeque
* @since 1.6
*/
public String(byte[] data, int offset, int byteCount, Charset charset) {
- if ((offset | byteCount) < 0 || byteCount > data.length - offset) {
- throw failedBoundsCheck(data.length, offset, byteCount);
- }
-
- // We inline UTF-8, ISO-8859-1, and US-ASCII decoders for speed and because 'count' and
- // 'value' are final.
- String canonicalCharsetName = charset.name();
- if (canonicalCharsetName.equals("UTF-8")) {
- byte[] d = data;
- char[] v = new char[byteCount];
-
- int idx = offset;
- int last = offset + byteCount;
- int s = 0;
-outer:
- while (idx < last) {
- byte b0 = d[idx++];
- if ((b0 & 0x80) == 0) {
- // 0xxxxxxx
- // Range: U-00000000 - U-0000007F
- int val = b0 & 0xff;
- v[s++] = (char) val;
- } else if (((b0 & 0xe0) == 0xc0) || ((b0 & 0xf0) == 0xe0) ||
- ((b0 & 0xf8) == 0xf0) || ((b0 & 0xfc) == 0xf8) || ((b0 & 0xfe) == 0xfc)) {
- int utfCount = 1;
- if ((b0 & 0xf0) == 0xe0) utfCount = 2;
- else if ((b0 & 0xf8) == 0xf0) utfCount = 3;
- else if ((b0 & 0xfc) == 0xf8) utfCount = 4;
- else if ((b0 & 0xfe) == 0xfc) utfCount = 5;
-
- // 110xxxxx (10xxxxxx)+
- // Range: U-00000080 - U-000007FF (count == 1)
- // Range: U-00000800 - U-0000FFFF (count == 2)
- // Range: U-00010000 - U-001FFFFF (count == 3)
- // Range: U-00200000 - U-03FFFFFF (count == 4)
- // Range: U-04000000 - U-7FFFFFFF (count == 5)
-
- if (idx + utfCount > last) {
- v[s++] = REPLACEMENT_CHAR;
- continue;
- }
-
- // Extract usable bits from b0
- int val = b0 & (0x1f >> (utfCount - 1));
- for (int i = 0; i < utfCount; ++i) {
- byte b = d[idx++];
- if ((b & 0xc0) != 0x80) {
- v[s++] = REPLACEMENT_CHAR;
- idx--; // Put the input char back
- continue outer;
- }
- // Push new bits in from the right side
- val <<= 6;
- val |= b & 0x3f;
- }
-
- // Note: Java allows overlong char
- // specifications To disallow, check that val
- // is greater than or equal to the minimum
- // value for each count:
- //
- // count min value
- // ----- ----------
- // 1 0x80
- // 2 0x800
- // 3 0x10000
- // 4 0x200000
- // 5 0x4000000
-
- // Allow surrogate values (0xD800 - 0xDFFF) to
- // be specified using 3-byte UTF values only
- if ((utfCount != 2) && (val >= 0xD800) && (val <= 0xDFFF)) {
- v[s++] = REPLACEMENT_CHAR;
- continue;
- }
-
- // Reject chars greater than the Unicode maximum of U+10FFFF.
- if (val > 0x10FFFF) {
- v[s++] = REPLACEMENT_CHAR;
- continue;
- }
-
- // Encode chars from U+10000 up as surrogate pairs
- if (val < 0x10000) {
- v[s++] = (char) val;
- } else {
- int x = val & 0xffff;
- int u = (val >> 16) & 0x1f;
- int w = (u - 1) & 0xffff;
- int hi = 0xd800 | (w << 6) | (x >> 10);
- int lo = 0xdc00 | (x & 0x3ff);
- v[s++] = (char) hi;
- v[s++] = (char) lo;
- }
- } else {
- // Illegal values 0x8*, 0x9*, 0xa*, 0xb*, 0xfd-0xff
- v[s++] = REPLACEMENT_CHAR;
- }
- }
-
- if (s == byteCount) {
- // We guessed right, so we can use our temporary array as-is.
- this.offset = 0;
- this.value = v;
- this.count = s;
- } else {
- // Our temporary array was too big, so reallocate and copy.
- this.offset = 0;
- this.value = new char[s];
- this.count = s;
- System.arraycopy(v, 0, value, 0, s);
- }
- } else if (canonicalCharsetName.equals("ISO-8859-1")) {
- this.offset = 0;
- this.value = new char[byteCount];
- this.count = byteCount;
- Charsets.isoLatin1BytesToChars(data, offset, byteCount, value);
- } else if (canonicalCharsetName.equals("US-ASCII")) {
- this.offset = 0;
- this.value = new char[byteCount];
- this.count = byteCount;
- Charsets.asciiBytesToChars(data, offset, byteCount, value);
- } else {
- CharBuffer cb = charset.decode(ByteBuffer.wrap(data, offset, byteCount));
- this.offset = 0;
- this.count = cb.length();
- if (count > 0) {
- // We could use cb.array() directly, but that would mean we'd have to trust
- // the CharsetDecoder doesn't hang on to the CharBuffer and mutate it later,
- // which would break String's immutability guarantee. It would also tend to
- // mean that we'd be wasting memory because CharsetDecoder doesn't trim the
- // array. So we copy.
- this.value = new char[count];
- System.arraycopy(cb.array(), 0, value, 0, count);
- } else {
- this.value = EmptyArray.CHAR;
- }
- }
+ throw new UnsupportedOperationException("Use StringFactory instead.");
}
/**
@@ -368,7 +199,7 @@ outer:
* @since 1.6
*/
public String(byte[] data, Charset charset) {
- this(data, 0, data.length, charset);
+ throw new UnsupportedOperationException("Use StringFactory instead.");
}
/**
@@ -379,7 +210,7 @@ outer:
* @throws NullPointerException if {@code data == null}
*/
public String(char[] data) {
- this(data, 0, data.length);
+ throw new UnsupportedOperationException("Use StringFactory instead.");
}
/**
@@ -393,36 +224,25 @@ outer:
* if {@code charCount < 0 || offset < 0 || offset + charCount > data.length}
*/
public String(char[] data, int offset, int charCount) {
- if ((offset | charCount) < 0 || charCount > data.length - offset) {
- throw failedBoundsCheck(data.length, offset, charCount);
- }
- this.offset = 0;
- this.value = new char[charCount];
- this.count = charCount;
- System.arraycopy(data, offset, value, 0, count);
+ throw new UnsupportedOperationException("Use StringFactory instead.");
}
/*
* Internal version of the String(char[], int, int) constructor.
- * Does not range check, null check, or copy the array.
+ * Does not range check or null check.
*/
+ // TODO: Replace calls to this with calls to StringFactory, will require
+ // splitting other files in java.lang.
String(int offset, int charCount, char[] chars) {
- this.value = chars;
- this.offset = offset;
- this.count = charCount;
+ throw new UnsupportedOperationException("Use StringFactory instead.");
}
/**
- * Constructs a copy of the given string.
- * The returned string's <a href="#backing_array">backing array</a>
- * is no larger than necessary.
+ * Constructs a new string with the same sequence of characters as {@code
+ * toCopy}.
*/
public String(String toCopy) {
- value = (toCopy.value.length == toCopy.count)
- ? toCopy.value
- : Arrays.copyOfRange(toCopy.value, toCopy.offset, toCopy.offset + toCopy.length());
- offset = 0;
- count = value.length;
+ throw new UnsupportedOperationException("Use StringFactory instead.");
}
/**
@@ -430,11 +250,7 @@ outer:
* {@code StringBuffer}.
*/
public String(StringBuffer stringBuffer) {
- offset = 0;
- synchronized (stringBuffer) {
- value = stringBuffer.shareValue();
- count = stringBuffer.length();
- }
+ throw new UnsupportedOperationException("Use StringFactory instead.");
}
/**
@@ -451,20 +267,7 @@ outer:
* @since 1.5
*/
public String(int[] codePoints, int offset, int count) {
- if (codePoints == null) {
- throw new NullPointerException("codePoints == null");
- }
- if ((offset | count) < 0 || count > codePoints.length - offset) {
- throw failedBoundsCheck(codePoints.length, offset, count);
- }
- this.offset = 0;
- this.value = new char[count * 2];
- int end = offset + count;
- int c = 0;
- for (int i = offset; i < end; i++) {
- c += Character.toChars(codePoints[i], this.value, c);
- }
- this.count = c;
+ throw new UnsupportedOperationException("Use StringFactory instead.");
}
/**
@@ -476,25 +279,16 @@ outer:
* @since 1.5
*/
public String(StringBuilder stringBuilder) {
- if (stringBuilder == null) {
- throw new NullPointerException("stringBuilder == null");
- }
- this.offset = 0;
- this.count = stringBuilder.length();
- this.value = new char[this.count];
- stringBuilder.getChars(0, this.count, this.value, 0);
+ throw new UnsupportedOperationException("Use StringFactory instead.");
}
/**
* Returns the {@code char} at {@code index}.
* @throws IndexOutOfBoundsException if {@code index < 0} or {@code index >= length()}.
*/
- public char charAt(int index) {
- if (index < 0 || index >= count) {
- throw indexAndLength(index);
- }
- return value[offset + index];
- }
+ public native char charAt(int index);
+
+ native void setCharAt(int index, char c);
private StringIndexOutOfBoundsException indexAndLength(int index) {
throw new StringIndexOutOfBoundsException(this, index);
@@ -557,12 +351,11 @@ outer:
* if {@code string} is {@code null}.
*/
public int compareToIgnoreCase(String string) {
- int o1 = offset, o2 = string.offset, result;
- int end = offset + (count < string.count ? count : string.count);
+ int result;
+ int end = count < string.count ? count : string.count;
char c1, c2;
- char[] target = string.value;
- while (o1 < end) {
- if ((c1 = value[o1++]) == (c2 = target[o2++])) {
+ for (int i = 0; i < end; ++i) {
+ if ((c1 = charAt(i)) == (c2 = string.charAt(i))) {
continue;
}
c1 = foldCase(c1);
@@ -582,15 +375,7 @@ outer:
* @return a new string which is the concatenation of this string and the
* specified string.
*/
- public String concat(String string) {
- if (string.count > 0 && count > 0) {
- char[] buffer = new char[count + string.count];
- System.arraycopy(value, offset, buffer, 0, count);
- System.arraycopy(string.value, string.offset, buffer, count, string.count);
- return new String(0, buffer.length, buffer);
- }
- return count == 0 ? string : this;
- }
+ public native String concat(String string);
/**
* Creates a new string by copying the given {@code char[]}.
@@ -601,7 +386,7 @@ outer:
* if {@code data} is {@code null}.
*/
public static String copyValueOf(char[] data) {
- return new String(data, 0, data.length);
+ return StringFactory.newStringFromChars(data, 0, data.length);
}
/**
@@ -616,7 +401,7 @@ outer:
* data.length}.
*/
public static String copyValueOf(char[] data, int start, int length) {
- return new String(data, start, length);
+ return StringFactory.newStringFromChars(data, start, length);
}
/**
@@ -654,16 +439,10 @@ outer:
if (hashCode() != s.hashCode()) {
return false;
}
- char[] value1 = value;
- int offset1 = offset;
- char[] value2 = s.value;
- int offset2 = s.offset;
- for (int end = offset1 + count; offset1 < end; ) {
- if (value1[offset1] != value2[offset2]) {
+ for (int i = 0; i < count; ++i) {
+ if (charAt(i) != s.charAt(i)) {
return false;
}
- offset1++;
- offset2++;
}
return true;
} else {
@@ -686,12 +465,9 @@ outer:
if (string == null || count != string.count) {
return false;
}
- int o1 = offset, o2 = string.offset;
- int end = offset + count;
- char[] target = string.value;
- while (o1 < end) {
- char c1 = value[o1++];
- char c2 = target[o2++];
+ for (int i = 0; i < count; ++i) {
+ char c1 = charAt(i);
+ char c2 = string.charAt(i);
if (c1 != c2 && foldCase(c1) != foldCase(c2)) {
return false;
}
@@ -721,10 +497,9 @@ outer:
@Deprecated
public void getBytes(int start, int end, byte[] data, int index) {
if (start >= 0 && start <= end && end <= count) {
- end += offset;
try {
- for (int i = offset + start; i < end; i++) {
- data[index++] = (byte) value[i];
+ for (int i = start; i < end; ++i) {
+ data[index++] = (byte) charAt(i);
}
} catch (ArrayIndexOutOfBoundsException ignored) {
throw failedBoundsCheck(data.length, index, end - start);
@@ -772,16 +547,15 @@ outer:
public byte[] getBytes(Charset charset) {
String canonicalCharsetName = charset.name();
if (canonicalCharsetName.equals("UTF-8")) {
- return Charsets.toUtf8Bytes(value, offset, count);
+ return CharsetUtils.toUtf8Bytes(this, 0, count);
} else if (canonicalCharsetName.equals("ISO-8859-1")) {
- return Charsets.toIsoLatin1Bytes(value, offset, count);
+ return CharsetUtils.toIsoLatin1Bytes(this, 0, count);
} else if (canonicalCharsetName.equals("US-ASCII")) {
- return Charsets.toAsciiBytes(value, offset, count);
+ return CharsetUtils.toAsciiBytes(this, 0, count);
} else if (canonicalCharsetName.equals("UTF-16BE")) {
- return Charsets.toBigEndianUtf16Bytes(value, offset, count);
+ return CharsetUtils.toBigEndianUtf16Bytes(this, 0, count);
} else {
- CharBuffer chars = CharBuffer.wrap(this.value, this.offset, this.count);
- ByteBuffer buffer = charset.encode(chars.asReadOnlyBuffer());
+ ByteBuffer buffer = charset.encode(this);
byte[] bytes = new byte[buffer.limit()];
buffer.get(bytes);
return bytes;
@@ -809,7 +583,16 @@ outer:
*/
public void getChars(int start, int end, char[] buffer, int index) {
if (start >= 0 && start <= end && end <= count) {
- System.arraycopy(value, start + offset, buffer, index, end - start);
+ if (buffer == null) {
+ throw new NullPointerException("buffer == null");
+ }
+ if (index < 0) {
+ throw new IndexOutOfBoundsException("index < 0");
+ }
+ if (end - start > buffer.length - index) {
+ throw new ArrayIndexOutOfBoundsException("end - start > buffer.length - index");
+ }
+ getCharsNoCheck(start, end, buffer, index);
} else {
// We throw StringIndexOutOfBoundsException rather than System.arraycopy's AIOOBE.
throw startEndAndLength(start, end);
@@ -821,9 +604,7 @@ outer:
* within the java.lang package only. The caller is responsible for
* ensuring that start >= 0 && start <= end && end <= count.
*/
- void _getChars(int start, int end, char[] buffer, int index) {
- System.arraycopy(value, start + offset, buffer, index, end - start);
- }
+ native void getCharsNoCheck(int start, int end, char[] buffer, int index);
@Override public int hashCode() {
int hash = hashCode;
@@ -831,10 +612,8 @@ outer:
if (count == 0) {
return 0;
}
- final int end = count + offset;
- final char[] chars = value;
- for (int i = offset; i < end; ++i) {
- hash = 31*hash + chars[i];
+ for (int i = 0; i < count; ++i) {
+ hash = 31 * hash + charAt(i);
}
hashCode = hash;
}
@@ -893,21 +672,17 @@ outer:
if (subCount > _count) {
return -1;
}
- char[] target = string.value;
- int subOffset = string.offset;
- char firstChar = target[subOffset];
- int end = subOffset + subCount;
+ char firstChar = string.charAt(0);
while (true) {
int i = indexOf(firstChar, start);
if (i == -1 || subCount + i > _count) {
return -1; // handles subCount > count || start >= count
}
- int o1 = offset + i, o2 = subOffset;
- char[] _value = value;
- while (++o2 < end && _value[++o1] == target[o2]) {
+ int o1 = i, o2 = 0;
+ while (++o2 < subCount && charAt(++o1) == string.charAt(o2)) {
// Intentionally empty
}
- if (o2 == end) {
+ if (o2 == subCount) {
return i;
}
start = i + 1;
@@ -934,21 +709,17 @@ outer:
if (subCount + start > _count) {
return -1;
}
- char[] target = subString.value;
- int subOffset = subString.offset;
- char firstChar = target[subOffset];
- int end = subOffset + subCount;
+ char firstChar = subString.charAt(0);
while (true) {
int i = indexOf(firstChar, start);
if (i == -1 || subCount + i > _count) {
return -1; // handles subCount > count || start >= count
}
- int o1 = offset + i, o2 = subOffset;
- char[] _value = value;
- while (++o2 < end && _value[++o1] == target[o2]) {
+ int o1 = i, o2 = 0;
+ while (++o2 < subCount && charAt(++o1) == subString.charAt(o2)) {
// Intentionally empty
}
- if (o2 == end) {
+ if (o2 == subCount) {
return i;
}
start = i + 1;
@@ -991,11 +762,9 @@ outer:
return lastIndexOfSupplementary(c, Integer.MAX_VALUE);
}
int _count = count;
- int _offset = offset;
- char[] _value = value;
- for (int i = _offset + _count - 1; i >= _offset; --i) {
- if (_value[i] == c) {
- return i - _offset;
+ for (int i = _count - 1; i >= 0; --i) {
+ if (charAt(i) == c) {
+ return i;
}
}
return -1;
@@ -1011,15 +780,13 @@ outer:
return lastIndexOfSupplementary(c, start);
}
int _count = count;
- int _offset = offset;
- char[] _value = value;
if (start >= 0) {
if (start >= _count) {
start = _count - 1;
}
- for (int i = _offset + start; i >= _offset; --i) {
- if (_value[i] == c) {
- return i - _offset;
+ for (int i = start; i >= 0; --i) {
+ if (charAt(i) == c) {
+ return i;
}
}
}
@@ -1031,7 +798,7 @@ outer:
return -1;
}
char[] chars = Character.toChars(c);
- String needle = new String(0, chars.length, chars);
+ String needle = StringFactory.newStringFromChars(0, chars.length, chars);
return lastIndexOf(needle, start);
}
@@ -1065,20 +832,17 @@ outer:
start = count - subCount;
}
// count and subCount are both >= 1
- char[] target = subString.value;
- int subOffset = subString.offset;
- char firstChar = target[subOffset];
- int end = subOffset + subCount;
+ char firstChar = subString.charAt(0);
while (true) {
int i = lastIndexOf(firstChar, start);
if (i == -1) {
return -1;
}
- int o1 = offset + i, o2 = subOffset;
- while (++o2 < end && value[++o1] == target[o2]) {
+ int o1 = i, o2 = 0;
+ while (++o2 < subCount && charAt(++o1) == subString.charAt(o2)) {
// Intentionally empty
}
- if (o2 == end) {
+ if (o2 == subCount) {
return i;
}
start = i - 1;
@@ -1121,11 +885,8 @@ outer:
if (length <= 0) {
return true;
}
- int o1 = offset + thisStart, o2 = string.offset + start;
- char[] value1 = value;
- char[] value2 = string.value;
for (int i = 0; i < length; ++i) {
- if (value1[o1 + i] != value2[o2 + i]) {
+ if (charAt(thisStart + i) != string.charAt(start + i)) {
return false;
}
}
@@ -1164,13 +925,10 @@ outer:
if (start < 0 || length > string.count - start) {
return false;
}
- thisStart += offset;
- start += string.offset;
int end = thisStart + length;
- char[] target = string.value;
while (thisStart < end) {
- char c1 = value[thisStart++];
- char c2 = target[start++];
+ char c1 = charAt(thisStart++);
+ char c2 = string.charAt(start++);
if (c1 != c2 && foldCase(c1) != foldCase(c2)) {
return false;
}
@@ -1182,29 +940,20 @@ outer:
* Returns a copy of this string after replacing occurrences of the given {@code char} with another.
*/
public String replace(char oldChar, char newChar) {
- char[] buffer = value;
- int _offset = offset;
+ String s = null;
int _count = count;
-
- int idx = _offset;
- int last = _offset + _count;
boolean copied = false;
- while (idx < last) {
- if (buffer[idx] == oldChar) {
+ for (int i = 0; i < _count; ++i) {
+ if (charAt(i) == oldChar) {
if (!copied) {
- char[] newBuffer = new char[_count];
- System.arraycopy(buffer, _offset, newBuffer, 0, _count);
- buffer = newBuffer;
- idx -= _offset;
- last -= _offset;
+ s = StringFactory.newStringFromString(this);
copied = true;
}
- buffer[idx] = newChar;
+ s.setCharAt(i, newChar);
}
- idx++;
}
- return copied ? new String(0, count, buffer) : this;
+ return copied ? s : this;
}
/**
@@ -1241,9 +990,8 @@ outer:
int resultLength = count + (count + 1) * replacementString.length();
StringBuilder result = new StringBuilder(resultLength);
result.append(replacementString);
- int end = offset + count;
- for (int i = offset; i != end; ++i) {
- result.append(value[i]);
+ for (int i = 0; i != count; ++i) {
+ result.append(charAt(i));
result.append(replacementString);
}
return result.toString();
@@ -1252,15 +1000,21 @@ outer:
StringBuilder result = new StringBuilder(count);
int searchStart = 0;
do {
- // Copy chars before the match...
- result.append(value, offset + searchStart, matchStart - searchStart);
+ // Copy characters before the match...
+ // TODO: Perform this faster than one char at a time?
+ for (int i = searchStart; i < matchStart; ++i) {
+ result.append(charAt(i));
+ }
// Insert the replacement...
result.append(replacementString);
// And skip over the match...
searchStart = matchStart + targetLength;
} while ((matchStart = indexOf(targetString, searchStart)) != -1);
// Copy any trailing chars...
- result.append(value, offset + searchStart, count - searchStart);
+ // TODO: Perform this faster than one char at a time?
+ for (int i = searchStart; i < count; ++i) {
+ result.append(charAt(i));
+ }
return result.toString();
}
@@ -1308,7 +1062,7 @@ outer:
return this;
}
if (start >= 0 && start <= count) {
- return new String(offset + start, count - start, value);
+ return fastSubstring(start, count - start);
}
throw indexAndLength(start);
}
@@ -1328,21 +1082,19 @@ outer:
}
// Fast range check.
if (start >= 0 && start <= end && end <= count) {
- return new String(offset + start, end - start, value);
+ return fastSubstring(start, end - start);
}
throw startEndAndLength(start, end);
}
+ private native String fastSubstring(int start, int length);
+
/**
* Returns a new {@code char} array containing a copy of the {@code char}s in this string.
* This is expensive and rarely useful. If you just want to iterate over the {@code char}s in
* the string, use {@link #charAt} instead.
*/
- public char[] toCharArray() {
- char[] buffer = new char[count];
- System.arraycopy(value, offset, buffer, 0, count);
- return buffer;
- }
+ public native char[] toCharArray();
/**
* Converts this string to lower case, using the rules of the user's default locale.
@@ -1351,7 +1103,7 @@ outer:
* @return a new lower case string, or {@code this} if it's already all lower case.
*/
public String toLowerCase() {
- return CaseMapper.toLowerCase(Locale.getDefault(), this, value, offset, count);
+ return CaseMapper.toLowerCase(Locale.getDefault(), this);
}
/**
@@ -1368,7 +1120,7 @@ outer:
* @return a new lower case string, or {@code this} if it's already all lower case.
*/
public String toLowerCase(Locale locale) {
- return CaseMapper.toLowerCase(locale, this, value, offset, count);
+ return CaseMapper.toLowerCase(locale, this);
}
/**
@@ -1386,7 +1138,7 @@ outer:
* @return a new upper case string, or {@code this} if it's already all upper case.
*/
public String toUpperCase() {
- return CaseMapper.toUpperCase(Locale.getDefault(), this, value, offset, count);
+ return CaseMapper.toUpperCase(Locale.getDefault(), this, count);
}
/**
@@ -1403,7 +1155,7 @@ outer:
* @return a new upper case string, or {@code this} if it's already all upper case.
*/
public String toUpperCase(Locale locale) {
- return CaseMapper.toUpperCase(locale, this, value, offset, count);
+ return CaseMapper.toUpperCase(locale, this, count);
}
/**
@@ -1411,18 +1163,18 @@ outer:
* the beginning or end.
*/
public String trim() {
- int start = offset, last = offset + count - 1;
+ int start = 0, last = count - 1;
int end = last;
- while ((start <= end) && (value[start] <= ' ')) {
+ while ((start <= end) && (charAt(start) <= ' ')) {
start++;
}
- while ((end >= start) && (value[end] <= ' ')) {
+ while ((end >= start) && (charAt(end) <= ' ')) {
end--;
}
- if (start == offset && end == last) {
+ if (start == 0 && end == last) {
return this;
}
- return new String(start, end - start + 1, value);
+ return fastSubstring(start, end - start + 1);
}
/**
@@ -1434,7 +1186,7 @@ outer:
* if {@code data} is {@code null}.
*/
public static String valueOf(char[] data) {
- return new String(data, 0, data.length);
+ return StringFactory.newStringFromChars(data, 0, data.length);
}
/**
@@ -1448,7 +1200,7 @@ outer:
* if {@code data} is {@code null}.
*/
public static String valueOf(char[] data, int start, int length) {
- return new String(data, start, length);
+ return StringFactory.newStringFromChars(data, start, length);
}
/**
@@ -1457,9 +1209,9 @@ outer:
public static String valueOf(char value) {
String s;
if (value < 128) {
- s = new String(value, 1, ASCII);
+ s = StringFactory.newStringFromChars(value, 1, ASCII);
} else {
- s = new String(0, 1, new char[] { value });
+ s = StringFactory.newStringFromChars(0, 1, new char[] { value });
}
s.hashCode = value;
return s;
@@ -1533,7 +1285,8 @@ outer:
if (count != size) {
return false;
}
- return regionMatches(0, new String(0, size, sb.getValue()), 0, size);
+ String s = StringFactory.newStringFromChars(0, size, sb.getValue());
+ return regionMatches(0, s, 0, size);
}
}
@@ -1682,7 +1435,7 @@ outer:
if (index < 0 || index >= count) {
throw indexAndLength(index);
}
- return Character.codePointAt(value, offset + index, offset + count);
+ return Character.codePointAt(this, index);
}
/**
@@ -1696,7 +1449,7 @@ outer:
if (index < 1 || index > count) {
throw indexAndLength(index);
}
- return Character.codePointBefore(value, offset + index, offset);
+ return Character.codePointBefore(this, index);
}
/**
@@ -1717,7 +1470,7 @@ outer:
if (start < 0 || end > count || start > end) {
throw startEndAndLength(start, end);
}
- return Character.codePointCount(value, offset + start, end - start);
+ return Character.codePointCount(this, start, end);
}
/**
@@ -1748,9 +1501,7 @@ outer:
* @since 1.5
*/
public int offsetByCodePoints(int index, int codePointOffset) {
- int s = index + offset;
- int r = Character.offsetByCodePoints(value, offset, count, s, codePointOffset);
- return r - offset;
+ return Character.offsetByCodePoints(this, index, codePointOffset);
}
/**
@@ -1816,31 +1567,26 @@ outer:
@SuppressWarnings("unused")
private static int indexOf(String haystackString, String needleString,
int cache, int md2, char lastChar) {
- char[] haystack = haystackString.value;
- int haystackOffset = haystackString.offset;
int haystackLength = haystackString.count;
- char[] needle = needleString.value;
- int needleOffset = needleString.offset;
int needleLength = needleString.count;
int needleLengthMinus1 = needleLength - 1;
- int haystackEnd = haystackOffset + haystackLength;
- outer_loop: for (int i = haystackOffset + needleLengthMinus1; i < haystackEnd;) {
- if (lastChar == haystack[i]) {
+ outer_loop: for (int i = needleLengthMinus1; i < haystackLength;) {
+ if (lastChar == haystackString.charAt(i)) {
for (int j = 0; j < needleLengthMinus1; ++j) {
- if (needle[j + needleOffset] != haystack[i + j
- - needleLengthMinus1]) {
+ if (needleString.charAt(j) !=
+ haystackString.charAt(i + j - needleLengthMinus1)) {
int skip = 1;
- if ((cache & (1 << haystack[i])) == 0) {
+ if ((cache & (1 << haystackString.charAt(i))) == 0) {
skip += j;
}
i += Math.max(md2, skip);
continue outer_loop;
}
}
- return i - needleLengthMinus1 - haystackOffset;
+ return i - needleLengthMinus1;
}
- if ((cache & (1 << haystack[i])) == 0) {
+ if ((cache & (1 << haystackString.charAt(i))) == 0) {
i += needleLengthMinus1;
}
i++;
diff --git a/libart/src/main/java/java/lang/StringFactory.java b/libart/src/main/java/java/lang/StringFactory.java
new file mode 100644
index 0000000..4fc3eba
--- /dev/null
+++ b/libart/src/main/java/java/lang/StringFactory.java
@@ -0,0 +1,251 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package java.lang;
+
+import java.io.Serializable;
+import java.io.UnsupportedEncodingException;
+import java.nio.ByteBuffer;
+import java.nio.CharBuffer;
+import java.nio.charset.Charset;
+import java.util.Arrays;
+import java.util.Comparator;
+import libcore.util.CharsetUtils;
+import libcore.util.EmptyArray;
+
+/**
+ * Class used to generate strings instead of calling String.&lt;init>.
+ *
+ * @hide
+ */
+public final class StringFactory {
+
+ // TODO: Remove once native methods are in place.
+ private static final char REPLACEMENT_CHAR = (char) 0xfffd;
+
+ public static String newEmptyString() {
+ return newStringFromChars(EmptyArray.CHAR, 0, 0);
+ }
+
+ public static String newStringFromBytes(byte[] data) {
+ return newStringFromBytes(data, 0, data.length);
+ }
+
+ public static String newStringFromBytes(byte[] data, int high) {
+ return newStringFromBytes(data, high, 0, data.length);
+ }
+
+ public static String newStringFromBytes(byte[] data, int offset, int byteCount) {
+ return newStringFromBytes(data, offset, byteCount, Charset.defaultCharset());
+ }
+
+ public static native String newStringFromBytes(byte[] data, int high, int offset, int byteCount);
+
+ public static String newStringFromBytes(byte[] data, int offset, int byteCount, String charsetName) throws UnsupportedEncodingException {
+ return newStringFromBytes(data, offset, byteCount, Charset.forNameUEE(charsetName));
+ }
+
+ public static String newStringFromBytes(byte[] data, String charsetName) throws UnsupportedEncodingException {
+ return newStringFromBytes(data, 0, data.length, Charset.forNameUEE(charsetName));
+ }
+
+ // TODO: Implement this method natively.
+ public static String newStringFromBytes(byte[] data, int offset, int byteCount, Charset charset) {
+ if ((offset | byteCount) < 0 || byteCount > data.length - offset) {
+ throw new StringIndexOutOfBoundsException(data.length, offset, byteCount);
+ }
+
+ char[] value;
+ int length;
+
+ // We inline UTF-8, ISO-8859-1, and US-ASCII decoders for speed.
+ String canonicalCharsetName = charset.name();
+ if (canonicalCharsetName.equals("UTF-8")) {
+ byte[] d = data;
+ char[] v = new char[byteCount];
+
+ int idx = offset;
+ int last = offset + byteCount;
+ int s = 0;
+outer:
+ while (idx < last) {
+ byte b0 = d[idx++];
+ if ((b0 & 0x80) == 0) {
+ // 0xxxxxxx
+ // Range: U-00000000 - U-0000007F
+ int val = b0 & 0xff;
+ v[s++] = (char) val;
+ } else if (((b0 & 0xe0) == 0xc0) || ((b0 & 0xf0) == 0xe0) ||
+ ((b0 & 0xf8) == 0xf0) || ((b0 & 0xfc) == 0xf8) || ((b0 & 0xfe) == 0xfc)) {
+ int utfCount = 1;
+ if ((b0 & 0xf0) == 0xe0) utfCount = 2;
+ else if ((b0 & 0xf8) == 0xf0) utfCount = 3;
+ else if ((b0 & 0xfc) == 0xf8) utfCount = 4;
+ else if ((b0 & 0xfe) == 0xfc) utfCount = 5;
+
+ // 110xxxxx (10xxxxxx)+
+ // Range: U-00000080 - U-000007FF (count == 1)
+ // Range: U-00000800 - U-0000FFFF (count == 2)
+ // Range: U-00010000 - U-001FFFFF (count == 3)
+ // Range: U-00200000 - U-03FFFFFF (count == 4)
+ // Range: U-04000000 - U-7FFFFFFF (count == 5)
+
+ if (idx + utfCount > last) {
+ v[s++] = REPLACEMENT_CHAR;
+ continue;
+ }
+
+ // Extract usable bits from b0
+ int val = b0 & (0x1f >> (utfCount - 1));
+ for (int i = 0; i < utfCount; ++i) {
+ byte b = d[idx++];
+ if ((b & 0xc0) != 0x80) {
+ v[s++] = REPLACEMENT_CHAR;
+ idx--; // Put the input char back
+ continue outer;
+ }
+ // Push new bits in from the right side
+ val <<= 6;
+ val |= b & 0x3f;
+ }
+
+ // Note: Java allows overlong char
+ // specifications To disallow, check that val
+ // is greater than or equal to the minimum
+ // value for each count:
+ //
+ // count min value
+ // ----- ----------
+ // 1 0x80
+ // 2 0x800
+ // 3 0x10000
+ // 4 0x200000
+ // 5 0x4000000
+
+ // Allow surrogate values (0xD800 - 0xDFFF) to
+ // be specified using 3-byte UTF values only
+ if ((utfCount != 2) && (val >= 0xD800) && (val <= 0xDFFF)) {
+ v[s++] = REPLACEMENT_CHAR;
+ continue;
+ }
+
+ // Reject chars greater than the Unicode maximum of U+10FFFF.
+ if (val > 0x10FFFF) {
+ v[s++] = REPLACEMENT_CHAR;
+ continue;
+ }
+
+ // Encode chars from U+10000 up as surrogate pairs
+ if (val < 0x10000) {
+ v[s++] = (char) val;
+ } else {
+ int x = val & 0xffff;
+ int u = (val >> 16) & 0x1f;
+ int w = (u - 1) & 0xffff;
+ int hi = 0xd800 | (w << 6) | (x >> 10);
+ int lo = 0xdc00 | (x & 0x3ff);
+ v[s++] = (char) hi;
+ v[s++] = (char) lo;
+ }
+ } else {
+ // Illegal values 0x8*, 0x9*, 0xa*, 0xb*, 0xfd-0xff
+ v[s++] = REPLACEMENT_CHAR;
+ }
+ }
+
+ if (s == byteCount) {
+ // We guessed right, so we can use our temporary array as-is.
+ value = v;
+ length = s;
+ } else {
+ // Our temporary array was too big, so reallocate and copy.
+ value = new char[s];
+ length = s;
+ System.arraycopy(v, 0, value, 0, s);
+ }
+ } else if (canonicalCharsetName.equals("ISO-8859-1")) {
+ value = new char[byteCount];
+ length = byteCount;
+ CharsetUtils.isoLatin1BytesToChars(data, offset, byteCount, value);
+ } else if (canonicalCharsetName.equals("US-ASCII")) {
+ value = new char[byteCount];
+ length = byteCount;
+ CharsetUtils.asciiBytesToChars(data, offset, byteCount, value);
+ } else {
+ CharBuffer cb = charset.decode(ByteBuffer.wrap(data, offset, byteCount));
+ length = cb.length();
+ if (length > 0) {
+ // We could use cb.array() directly, but that would mean we'd have to trust
+ // the CharsetDecoder doesn't hang on to the CharBuffer and mutate it later,
+ // which would break String's immutability guarantee. It would also tend to
+ // mean that we'd be wasting memory because CharsetDecoder doesn't trim the
+ // array. So we copy.
+ value = new char[length];
+ System.arraycopy(cb.array(), 0, value, 0, length);
+ } else {
+ value = EmptyArray.CHAR;
+ }
+ }
+ return newStringFromChars(value, 0, length);
+ }
+
+ public static String newStringFromBytes(byte[] data, Charset charset) {
+ return newStringFromBytes(data, 0, data.length, charset);
+ }
+
+ public static String newStringFromChars(char[] data) {
+ return newStringFromChars(data, 0, data.length);
+ }
+
+ public static String newStringFromChars(char[] data, int offset, int charCount) {
+ if ((offset | charCount) < 0 || charCount > data.length - offset) {
+ throw new StringIndexOutOfBoundsException(data.length, offset, charCount);
+ }
+ return newStringFromChars(offset, charCount, data);
+ }
+
+ static native String newStringFromChars(int offset, int charCount, char[] data);
+
+ public static native String newStringFromString(String toCopy);
+
+ public static String newStringFromStringBuffer(StringBuffer stringBuffer) {
+ synchronized (stringBuffer) {
+ return newStringFromChars(stringBuffer.getValue(), 0, stringBuffer.length());
+ }
+ }
+
+ // TODO: Implement this method natively.
+ public static String newStringFromCodePoints(int[] codePoints, int offset, int count) {
+ if (codePoints == null) {
+ throw new NullPointerException("codePoints == null");
+ }
+ if ((offset | count) < 0 || count > codePoints.length - offset) {
+ throw new StringIndexOutOfBoundsException(codePoints.length, offset, count);
+ }
+ char[] value = new char[count * 2];
+ int end = offset + count;
+ int length = 0;
+ for (int i = offset; i < end; i++) {
+ length += Character.toChars(codePoints[i], value, length);
+ }
+ return newStringFromChars(value, 0, length);
+ }
+
+ public static String newStringFromStringBuilder(StringBuilder stringBuilder) {
+ return newStringFromChars(stringBuilder.getValue(), 0, stringBuilder.length());
+ }
+}
diff --git a/libart/src/main/java/java/lang/Thread.java b/libart/src/main/java/java/lang/Thread.java
index 852e2cf..7b3666b 100644
--- a/libart/src/main/java/java/lang/Thread.java
+++ b/libart/src/main/java/java/lang/Thread.java
@@ -1158,7 +1158,7 @@ public class Thread implements Runnable {
*
* @hide for Unsafe
*/
- public void unpark() {
+ public final void unpark$() {
synchronized (lock) {
switch (parkState) {
case ParkState.PREEMPTIVELY_UNPARKED: {
@@ -1204,7 +1204,7 @@ public class Thread implements Runnable {
*
* @hide for Unsafe
*/
- public void parkFor(long nanos) {
+ public final void parkFor$(long nanos) {
synchronized (lock) {
switch (parkState) {
case ParkState.PREEMPTIVELY_UNPARKED: {
@@ -1260,7 +1260,7 @@ public class Thread implements Runnable {
*
* @hide for Unsafe
*/
- public void parkUntil(long time) {
+ public final void parkUntil$(long time) {
synchronized (lock) {
/*
* Note: This conflates the two time bases of "wall clock"
@@ -1281,7 +1281,7 @@ public class Thread implements Runnable {
if (delayMillis <= 0) {
parkState = ParkState.UNPARKED;
} else {
- parkFor(delayMillis * NANOS_PER_MILLI);
+ parkFor$(delayMillis * NANOS_PER_MILLI);
}
}
}
diff --git a/libart/src/main/java/java/lang/reflect/AbstractMethod.java b/libart/src/main/java/java/lang/reflect/AbstractMethod.java
index 7e6491d..95d90cc 100644
--- a/libart/src/main/java/java/lang/reflect/AbstractMethod.java
+++ b/libart/src/main/java/java/lang/reflect/AbstractMethod.java
@@ -39,28 +39,39 @@ import libcore.reflect.AnnotationAccess;
import libcore.reflect.GenericSignatureParser;
import libcore.reflect.ListOfTypes;
import libcore.reflect.Types;
+import libcore.util.EmptyArray;
/**
* This class represents an abstract method. Abstract methods are either methods or constructors.
* @hide
*/
public abstract class AbstractMethod extends AccessibleObject {
+ /** Bits encoding access (e.g. public, private) as well as other runtime specific flags */
+ protected int accessFlags;
/**
+ * The ArtMethod associated with this Method, requried for dispatching due to entrypoints
+ * Classloader is held live by the declaring class.
* Hidden to workaround b/16828157.
* @hide
*/
- protected final ArtMethod artMethod;
+ protected long artMethod;
+
+ /** Method's declaring class */
+ protected Class<?> declaringClass;
+
+ /** Overriden method's declaring class (same as declaringClass unless declaringClass
+ * is a proxy class) */
+ protected Class<?> declaringClassOfOverriddenMethod;
+
+ /** The method index of this method within its defining dex file */
+ protected int dexMethodIndex;
/**
* Hidden to workaround b/16828157.
* @hide
*/
- protected AbstractMethod(ArtMethod artMethod) {
- if (artMethod == null) {
- throw new NullPointerException("artMethod == null");
- }
- this.artMethod = artMethod;
+ protected AbstractMethod() {
}
public <T extends Annotation> T getAnnotation(Class<T> annotationClass) {
@@ -90,33 +101,33 @@ public abstract class AbstractMethod extends AccessibleObject {
}
int getModifiers() {
- return fixMethodFlags(artMethod.getAccessFlags());
+ return fixMethodFlags(accessFlags);
}
boolean isVarArgs() {
- return (artMethod.getAccessFlags() & Modifier.VARARGS) != 0;
+ return (accessFlags & Modifier.VARARGS) != 0;
}
boolean isBridge() {
- return (artMethod.getAccessFlags() & Modifier.BRIDGE) != 0;
+ return (accessFlags & Modifier.BRIDGE) != 0;
}
boolean isSynthetic() {
- return (artMethod.getAccessFlags() & Modifier.SYNTHETIC) != 0;
+ return (accessFlags & Modifier.SYNTHETIC) != 0;
}
/**
* @hide
*/
public final int getAccessFlags() {
- return artMethod.getAccessFlags();
+ return accessFlags;
}
/**
* Returns the class that declares this constructor or method.
*/
Class<?> getDeclaringClass() {
- return artMethod.getDeclaringClass();
+ return declaringClass;
}
/**
@@ -125,7 +136,7 @@ public abstract class AbstractMethod extends AccessibleObject {
* @hide
*/
public final int getDexMethodIndex() {
- return artMethod.getDexMethodIndex();
+ return dexMethodIndex;
}
/**
@@ -144,7 +155,17 @@ public abstract class AbstractMethod extends AccessibleObject {
* @return the parameter types
*/
Class<?>[] getParameterTypes() {
- return artMethod.getParameterTypes();
+ Dex dex = declaringClassOfOverriddenMethod.getDex();
+ short[] types = dex.parameterTypeIndicesFromMethodIndex(dexMethodIndex);
+ if (types.length == 0) {
+ return EmptyArray.CLASS;
+ }
+ Class<?>[] parametersArray = new Class[types.length];
+ for (int i = 0; i < types.length; i++) {
+ // Note, in the case of a Proxy the dex cache types are equal.
+ parametersArray[i] = declaringClassOfOverriddenMethod.getDexCacheType(dex, types[i]);
+ }
+ return parametersArray;
}
/**
@@ -155,8 +176,10 @@ public abstract class AbstractMethod extends AccessibleObject {
if (!(other instanceof AbstractMethod)) {
return false;
}
- // exactly one instance of each member in this runtime
- return this.artMethod == ((AbstractMethod) other).artMethod;
+ // Exactly one instance of each member in this runtime, todo, does this work for proxies?
+ AbstractMethod otherMethod = (AbstractMethod) other;
+ return this.declaringClass == otherMethod.declaringClass &&
+ this.dexMethodIndex == otherMethod.dexMethodIndex;
}
String toGenericString() {
@@ -252,6 +275,37 @@ public abstract class AbstractMethod extends AccessibleObject {
parser.returnType, parser.formalTypeParameters);
}
+ protected boolean equalMethodParameters(Class<?>[] params) {
+ Dex dex = declaringClassOfOverriddenMethod.getDex();
+ short[] types = dex.parameterTypeIndicesFromMethodIndex(dexMethodIndex);
+ if (types.length != params.length) {
+ return false;
+ }
+ for (int i = 0; i < types.length; i++) {
+ if (declaringClassOfOverriddenMethod.getDexCacheType(dex, types[i]) != params[i]) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ protected int compareParameters(Class<?>[] params) {
+ Dex dex = declaringClassOfOverriddenMethod.getDex();
+ short[] types = dex.parameterTypeIndicesFromMethodIndex(dexMethodIndex);
+ int length = Math.min(types.length, params.length);
+ for (int i = 0; i < length; i++) {
+ Class<?> aType = declaringClassOfOverriddenMethod.getDexCacheType(dex, types[i]);
+ Class<?> bType = params[i];
+ if (aType != bType) {
+ int comparison = aType.getName().compareTo(bType.getName());
+ if (comparison != 0) {
+ return comparison;
+ }
+ }
+ }
+ return types.length - params.length;
+ }
+
/**
* Helper for Method and Constructor for toGenericString
*/
diff --git a/libart/src/main/java/java/lang/reflect/AccessibleObject.java b/libart/src/main/java/java/lang/reflect/AccessibleObject.java
index a1e2743..f623880 100644
--- a/libart/src/main/java/java/lang/reflect/AccessibleObject.java
+++ b/libart/src/main/java/java/lang/reflect/AccessibleObject.java
@@ -71,15 +71,8 @@ public class AccessibleObject implements AnnotatedElement {
* IllegalAccessExceptions}.
*/
public void setAccessible(boolean flag) {
- try {
- if (equals(Class.class.getDeclaredConstructor())) {
- throw new SecurityException("Can't make class constructor accessible");
- }
- } catch (NoSuchMethodException e) {
- throw new AssertionError("Couldn't find class constructor");
- }
this.flag = flag;
- }
+ }
/**
* Attempts to set the accessible flag for all objects in {@code objects}.
diff --git a/libart/src/main/java/java/lang/reflect/ArtField.java b/libart/src/main/java/java/lang/reflect/ArtField.java
deleted file mode 100644
index 6fdcdb2..0000000
--- a/libart/src/main/java/java/lang/reflect/ArtField.java
+++ /dev/null
@@ -1,96 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package java.lang.reflect;
-
-import com.android.dex.Dex;
-
-/**
- * @hide
- */
-public final class ArtField {
-
- private Class<?> declaringClass;
- /** Field access flags (modifiers) */
- private int accessFlags;
- /** Index into DexFile's field ids */
- private int fieldDexIndex;
- /** Offset of field in object or class */
- private int offset;
-
- /**
- * Only created by art directly.
- */
- private ArtField() {}
-
- public int getAccessFlags() {
- return accessFlags;
- }
-
- int getDexFieldIndex() {
- return fieldDexIndex;
- }
-
- int getOffset() {
- return offset;
- }
-
- public String getName() {
- if (fieldDexIndex == -1) {
- // Proxy classes have 1 synthesized static field with no valid dex index
- if (!declaringClass.isProxy()) {
- throw new AssertionError();
- }
- return "throws";
- }
- Dex dex = declaringClass.getDex();
- int nameIndex = dex.nameIndexFromFieldIndex(fieldDexIndex);
- return declaringClass.getDexCacheString(dex, nameIndex);
- }
-
- Class<?> getDeclaringClass() {
- return declaringClass;
- }
-
- Class<?> getType() {
- if (fieldDexIndex == -1) {
- // The type of the synthesized field in a Proxy class is Class[][]
- if (!declaringClass.isProxy()) {
- throw new AssertionError();
- }
- return Class[][].class;
- }
- Dex dex = declaringClass.getDex();
- int typeIndex = dex.typeIndexFromFieldIndex(fieldDexIndex);
- return declaringClass.getDexCacheType(dex, typeIndex);
- }
-}
diff --git a/libart/src/main/java/java/lang/reflect/ArtMethod.java b/libart/src/main/java/java/lang/reflect/ArtMethod.java
deleted file mode 100644
index 95e03c6..0000000
--- a/libart/src/main/java/java/lang/reflect/ArtMethod.java
+++ /dev/null
@@ -1,212 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package java.lang.reflect;
-
-import com.android.dex.Dex;
-import java.lang.annotation.Annotation;
-import libcore.reflect.AnnotationAccess;
-import libcore.util.EmptyArray;
-
-/**
- * This class represents methods and constructors.
- * @hide
- */
-public final class ArtMethod {
- /* A note on the field order here, it reflects the same field order as laid out by ART. */
-
- /** Method's declaring class */
- private Class<?> declaringClass;
-
- /** Short-cut to declaringClass.dexCache.resolvedMethods */
- private ArtMethod[] dexCacheResolvedMethods;
-
- /** Short-cut to declaringClass.dexCache.resolvedTypes */
- /* package */ Class<?>[] dexCacheResolvedTypes;
-
- /** Bits encoding access (e.g. public, private) as well as other runtime specific flags */
- private int accessFlags;
-
- /* Dex file fields. The defining dex file is available via declaringClass.dexCache */
-
- /** The offset of the code item associated with this method within its defining dex file */
- private int dexCodeItemOffset;
-
- /** The method index of this method within its defining dex file */
- private int dexMethodIndex;
-
- /* End of dex file fields. */
-
- /**
- * Entry within a dispatch table for this method. For static/direct methods the index is
- * into the declaringClass.directMethods, for virtual methods the vtable and for
- * interface methods the ifTable.
- */
- private int methodIndex;
-
- /** Only created by ART directly. */
- private ArtMethod() {}
-
- Class getDeclaringClass() {
- return declaringClass;
- }
-
- public int getAccessFlags() {
- return accessFlags;
- }
-
- int getDexMethodIndex() {
- return dexMethodIndex;
- }
-
- public static String getMethodName(ArtMethod artMethod) {
- artMethod = artMethod.findOverriddenMethodIfProxy();
- Dex dex = artMethod.getDeclaringClass().getDex();
- int nameIndex = dex.nameIndexFromMethodIndex(artMethod.getDexMethodIndex());
- // Note, in the case of a Proxy the dex cache strings are equal.
- return artMethod.getDexCacheString(dex, nameIndex);
- }
-
- /**
- * Returns true if the given parameters match those of the method in the given order.
- *
- * @hide
- */
- public static boolean equalConstructorParameters(ArtMethod artMethod, Class<?>[] params) {
- Dex dex = artMethod.getDeclaringClass().getDex();
- short[] types = dex.parameterTypeIndicesFromMethodIndex(artMethod.getDexMethodIndex());
- if (types.length != params.length) {
- return false;
- }
- for (int i = 0; i < types.length; i++) {
- if (artMethod.getDexCacheType(dex, types[i]) != params[i]) {
- return false;
- }
- }
- return true;
- }
-
- /**
- * Returns true if the given parameters match those of this method in the given order.
- *
- * @hide
- */
- public static boolean equalMethodParameters(ArtMethod artMethod, Class<?>[] params) {
- return equalConstructorParameters(artMethod.findOverriddenMethodIfProxy(), params);
- }
-
- Class<?>[] getParameterTypes() {
- Dex dex = getDeclaringClass().getDex();
- short[] types = dex.parameterTypeIndicesFromMethodIndex(dexMethodIndex);
- if (types.length == 0) {
- return EmptyArray.CLASS;
- }
- Class<?>[] parametersArray = new Class[types.length];
- for (int i = 0; i < types.length; i++) {
- // Note, in the case of a Proxy the dex cache types are equal.
- parametersArray[i] = getDexCacheType(dex, types[i]);
- }
- return parametersArray;
- }
-
- Class<?> getReturnType() {
- Dex dex = declaringClass.getDex();
- int returnTypeIndex = dex.returnTypeIndexFromMethodIndex(dexMethodIndex);
- // Note, in the case of a Proxy the dex cache types are equal.
- return getDexCacheType(dex, returnTypeIndex);
- }
-
- /**
- * Performs a comparison of the parameters to this method with the given parameters.
- *
- * @hide
- */
- int compareParameters(Class<?>[] params) {
- Dex dex = getDeclaringClass().getDex();
- short[] types = dex.parameterTypeIndicesFromMethodIndex(dexMethodIndex);
- int length = Math.min(types.length, params.length);
- for (int i = 0; i < length; i++) {
- Class<?> aType = getDexCacheType(dex, types[i]);
- Class<?> bType = params[i];
- if (aType != bType) {
- int comparison = aType.getName().compareTo(bType.getName());
- if (comparison != 0) {
- return comparison;
- }
- }
- }
- return types.length - params.length;
- }
-
- Annotation[][] getParameterAnnotations() {
- return AnnotationAccess.getParameterAnnotations(declaringClass, dexMethodIndex);
- }
-
- /**
- * Returns a string from the dex cache, computing the string from the dex file if necessary.
- * Note this method replicates {@link java.lang.Class#getDexCacheString(Dex, int)}, but in
- * Method we can avoid one indirection.
- */
- private String getDexCacheString(Dex dex, int dexStringIndex) {
- return declaringClass.getDexCacheString(dex, dexStringIndex);
- }
-
- /**
- * Returns a resolved type from the dex cache, computing the string from the dex file if
- * necessary. Note this method delegates to {@link java.lang.Class#getDexCacheType(Dex, int)},
- * but in Method we can avoid one indirection.
- */
- private Class<?> getDexCacheType(Dex dex, int dexTypeIndex) {
- Class<?> resolvedType = dexCacheResolvedTypes[dexTypeIndex];
- if (resolvedType == null) {
- resolvedType = declaringClass.getDexCacheType(dex, dexTypeIndex);
- }
- return resolvedType;
- }
-
- /**
- * Returns the {@code ArtMethod} that this method overrides for
- * proxy methods, otherwise returns this method. Used to determine
- * the interface method overridden by a proxy method (as the proxy
- * method doesn't directly support operations such as {@link
- * Method#getName}).
- */
- ArtMethod findOverriddenMethodIfProxy() {
- if (declaringClass.isProxy()) {
- // Proxy method's declaring class' dex cache refers to that of Proxy. The local cache in
- // Method refers to the original interface's dex cache and is ensured to be resolved by
- // proxy generation.
- return dexCacheResolvedMethods[dexMethodIndex];
- }
- return this;
- }
-}
diff --git a/libart/src/main/java/java/lang/reflect/Constructor.java b/libart/src/main/java/java/lang/reflect/Constructor.java
index 2eb12b0..9711ef4 100644
--- a/libart/src/main/java/java/lang/reflect/Constructor.java
+++ b/libart/src/main/java/java/lang/reflect/Constructor.java
@@ -49,11 +49,7 @@ public final class Constructor<T> extends AbstractMethod implements GenericDecla
private static final Comparator<Method> ORDER_BY_SIGNATURE = null; // Unused; must match Method.
- /**
- * @hide
- */
- public Constructor(ArtMethod artMethod) {
- super(artMethod);
+ private Constructor() {
}
public Annotation[] getAnnotations() {
@@ -213,7 +209,8 @@ public final class Constructor<T> extends AbstractMethod implements GenericDecla
* @return an array of arrays of {@code Annotation} instances
*/
public Annotation[][] getParameterAnnotations() {
- return artMethod.getParameterAnnotations();
+ return AnnotationAccess.getParameterAnnotations(
+ declaringClassOfOverriddenMethod, dexMethodIndex);
}
/**
@@ -283,13 +280,7 @@ public final class Constructor<T> extends AbstractMethod implements GenericDecla
*
* @see AccessibleObject
*/
- public T newInstance(Object... args) throws InstantiationException,
- IllegalAccessException, IllegalArgumentException, InvocationTargetException {
- return newInstance(args, isAccessible());
- }
-
- /** @hide */
- public native T newInstance(Object[] args, boolean accessible) throws InstantiationException,
+ public native T newInstance(Object... args) throws InstantiationException,
IllegalAccessException, IllegalArgumentException, InvocationTargetException;
/**
@@ -330,4 +321,20 @@ public final class Constructor<T> extends AbstractMethod implements GenericDecla
return result.toString();
}
+
+ /**
+ * Attempts to set the accessible flag. Setting this to true prevents {@code
+ * IllegalAccessExceptions}.
+ */
+ public void setAccessible(boolean flag) {
+ Class<?> declaringClass = getDeclaringClass();
+ if (declaringClass == Class.class) {
+ throw new SecurityException("Can't make class constructor accessible");
+ } else if (declaringClass == Field.class) {
+ throw new SecurityException("Can't make field constructor accessible");
+ } else if (declaringClass == Method.class) {
+ throw new SecurityException("Can't make method constructor accessible");
+ }
+ super.setAccessible(flag);
+ }
}
diff --git a/libart/src/main/java/java/lang/reflect/Field.java b/libart/src/main/java/java/lang/reflect/Field.java
index 11e8a6e..37f2ad0 100644
--- a/libart/src/main/java/java/lang/reflect/Field.java
+++ b/libart/src/main/java/java/lang/reflect/Field.java
@@ -71,16 +71,13 @@ public final class Field extends AccessibleObject implements Member {
}
};
- private final ArtField artField;
+ private int accessFlags;
+ private Class<?> declaringClass;
+ private int dexFieldIndex;
+ private int offset;
+ private Class<?> type;
- /**
- * @hide
- */
- public Field(ArtField artField) {
- if (artField == null) {
- throw new NullPointerException("artField == null");
- }
- this.artField = artField;
+ private Field() {
}
/**
@@ -91,7 +88,7 @@ public final class Field extends AccessibleObject implements Member {
* @see Modifier
*/
@Override public int getModifiers() {
- return artField.getAccessFlags() & 0xffff; // mask out bits not used by Java
+ return accessFlags & 0xffff; // mask out bits not used by Java
}
/**
@@ -101,7 +98,7 @@ public final class Field extends AccessibleObject implements Member {
* false} otherwise
*/
public boolean isEnumConstant() {
- return (artField.getAccessFlags() & Modifier.ENUM) != 0;
+ return (accessFlags & Modifier.ENUM) != 0;
}
/**
@@ -110,7 +107,7 @@ public final class Field extends AccessibleObject implements Member {
* @return {@code true} if this field is synthetic, {@code false} otherwise
*/
@Override public boolean isSynthetic() {
- return (artField.getAccessFlags() & Modifier.SYNTHETIC) != 0;
+ return (accessFlags & Modifier.SYNTHETIC) != 0;
}
/**
@@ -119,11 +116,20 @@ public final class Field extends AccessibleObject implements Member {
* @return the name of this field
*/
@Override public String getName() {
- return artField.getName();
+ if (dexFieldIndex == -1) {
+ // Proxy classes have 1 synthesized static field with no valid dex index.
+ if (!declaringClass.isProxy()) {
+ throw new AssertionError();
+ }
+ return "throws";
+ }
+ Dex dex = declaringClass.getDex();
+ int nameIndex = dex.nameIndexFromFieldIndex(dexFieldIndex);
+ return declaringClass.getDexCacheString(dex, nameIndex);
}
@Override public Class<?> getDeclaringClass() {
- return artField.getDeclaringClass();
+ return declaringClass;
}
/**
@@ -132,7 +138,7 @@ public final class Field extends AccessibleObject implements Member {
* @return the type of this field
*/
public Class<?> getType() {
- return artField.getType();
+ return type;
}
/**
@@ -141,7 +147,7 @@ public final class Field extends AccessibleObject implements Member {
* @hide
*/
public int getDexFieldIndex() {
- return artField.getDexFieldIndex();
+ return dexFieldIndex;
}
/**
@@ -150,7 +156,7 @@ public final class Field extends AccessibleObject implements Member {
* @hide
*/
public int getOffset() {
- return artField.getOffset();
+ return offset;
}
/**
@@ -170,8 +176,10 @@ public final class Field extends AccessibleObject implements Member {
if (!(other instanceof Field)) {
return false;
}
- // exactly one instance of each member in this runtime
- return this.artField == ((Field) other).artField;
+ // Given same declaring class and offset, it must be the same field since no two distinct
+ // fields can have the same offset.
+ Field field = (Field)other;
+ return this.declaringClass == field.declaringClass && this.offset == field.offset;
}
/**
@@ -182,10 +190,12 @@ public final class Field extends AccessibleObject implements Member {
*/
public String toGenericString() {
StringBuilder sb = new StringBuilder(80);
+ // Limit modifier bits to the ones that toStringGeneric should return for fields.
+
+ String modifiers = Modifier.getDeclarationFieldModifiers(getModifiers());
// append modifiers if any
- int modifier = getModifiers();
- if (modifier != 0) {
- sb.append(Modifier.toString(modifier)).append(' ');
+ if (!modifiers.isEmpty()) {
+ sb.append(modifiers).append(' ');
}
// append generic type
Types.appendGenericType(sb, getGenericType());
@@ -275,11 +285,7 @@ public final class Field extends AccessibleObject implements Member {
* @throws IllegalAccessException
* if this field is not accessible
*/
- public Object get(Object object) throws IllegalAccessException, IllegalArgumentException {
- return get(object, isAccessible());
- }
-
- private native Object get(Object object, boolean accessible)
+ public native Object get(Object object)
throws IllegalAccessException, IllegalArgumentException;
/**
@@ -305,12 +311,7 @@ public final class Field extends AccessibleObject implements Member {
* @throws IllegalAccessException
* if this field is not accessible
*/
- public boolean getBoolean(Object object) throws IllegalAccessException,
- IllegalArgumentException {
- return getBoolean(object, isAccessible());
- }
-
- private native boolean getBoolean(Object object, boolean accessible)
+ public native boolean getBoolean(Object object)
throws IllegalAccessException, IllegalArgumentException;
/**
@@ -336,11 +337,7 @@ public final class Field extends AccessibleObject implements Member {
* @throws IllegalAccessException
* if this field is not accessible
*/
- public byte getByte(Object object) throws IllegalAccessException, IllegalArgumentException {
- return getByte(object, isAccessible());
- }
-
- private native byte getByte(Object object, boolean accessible)
+ public native byte getByte(Object object)
throws IllegalAccessException, IllegalArgumentException;
/**
@@ -366,11 +363,7 @@ public final class Field extends AccessibleObject implements Member {
* @throws IllegalAccessException
* if this field is not accessible
*/
- public char getChar(Object object) throws IllegalAccessException, IllegalArgumentException {
- return getChar(object, isAccessible());
- }
-
- private native char getChar(Object object, boolean accessible)
+ public native char getChar(Object object)
throws IllegalAccessException, IllegalArgumentException;
/**
@@ -396,11 +389,7 @@ public final class Field extends AccessibleObject implements Member {
* @throws IllegalAccessException
* if this field is not accessible
*/
- public double getDouble(Object object) throws IllegalAccessException, IllegalArgumentException {
- return getDouble(object, isAccessible());
- }
-
- private native double getDouble(Object object, boolean accessible)
+ public native double getDouble(Object object)
throws IllegalAccessException, IllegalArgumentException;
/**
@@ -426,11 +415,7 @@ public final class Field extends AccessibleObject implements Member {
* @throws IllegalAccessException
* if this field is not accessible
*/
- public float getFloat(Object object) throws IllegalAccessException, IllegalArgumentException {
- return getFloat(object, isAccessible());
- }
-
- private native float getFloat(Object object, boolean accessible)
+ public native float getFloat(Object object)
throws IllegalAccessException, IllegalArgumentException;
/**
@@ -456,11 +441,7 @@ public final class Field extends AccessibleObject implements Member {
* @throws IllegalAccessException
* if this field is not accessible
*/
- public int getInt(Object object) throws IllegalAccessException, IllegalArgumentException {
- return getInt(object, isAccessible());
- }
-
- private native int getInt(Object object, boolean accessible)
+ public native int getInt(Object object)
throws IllegalAccessException, IllegalArgumentException;
/**
@@ -486,11 +467,7 @@ public final class Field extends AccessibleObject implements Member {
* @throws IllegalAccessException
* if this field is not accessible
*/
- public long getLong(Object object) throws IllegalAccessException, IllegalArgumentException {
- return getLong(object, isAccessible());
- }
-
- private native long getLong(Object object, boolean accessible)
+ public native long getLong(Object object)
throws IllegalAccessException, IllegalArgumentException;
/**
@@ -516,11 +493,7 @@ public final class Field extends AccessibleObject implements Member {
* @throws IllegalAccessException
* if this field is not accessible
*/
- public short getShort(Object object) throws IllegalAccessException, IllegalArgumentException {
- return getShort(object, isAccessible());
- }
-
- private native short getShort(Object object, boolean accessible)
+ public native short getShort(Object object)
throws IllegalAccessException, IllegalArgumentException;
/**
@@ -552,12 +525,7 @@ public final class Field extends AccessibleObject implements Member {
* @throws IllegalAccessException
* if this field is not accessible
*/
- public void set(Object object, Object value) throws IllegalAccessException,
- IllegalArgumentException {
- set(object, value, isAccessible());
- }
-
- private native void set(Object object, Object value, boolean accessible)
+ public native void set(Object object, Object value)
throws IllegalAccessException, IllegalArgumentException;
/**
@@ -588,12 +556,7 @@ public final class Field extends AccessibleObject implements Member {
* @throws IllegalAccessException
* if this field is not accessible
*/
- public void setBoolean(Object object, boolean value) throws IllegalAccessException,
- IllegalArgumentException {
- setBoolean(object, value, isAccessible());
- }
-
- private native void setBoolean(Object object, boolean value, boolean accessible)
+ public native void setBoolean(Object object, boolean value)
throws IllegalAccessException, IllegalArgumentException;
/**
@@ -623,14 +586,8 @@ public final class Field extends AccessibleObject implements Member {
* @throws IllegalAccessException
* if this field is not accessible
*/
- public void setByte(Object object, byte value) throws IllegalAccessException,
- IllegalArgumentException {
- setByte(object, value, isAccessible());
- }
-
- private native void setByte(Object object, byte value, boolean accessible)
+ public native void setByte(Object object, byte value)
throws IllegalAccessException, IllegalArgumentException;
-
/**
* Sets the value of the field in the specified object to the {@code char}
* value. This reproduces the effect of {@code object.fieldName = value}
@@ -658,12 +615,7 @@ public final class Field extends AccessibleObject implements Member {
* @throws IllegalAccessException
* if this field is not accessible
*/
- public void setChar(Object object, char value) throws IllegalAccessException,
- IllegalArgumentException {
- setChar(object, value, isAccessible());
- }
-
- private native void setChar(Object object, char value, boolean accessible)
+ public native void setChar(Object object, char value)
throws IllegalAccessException, IllegalArgumentException;
/**
@@ -693,12 +645,7 @@ public final class Field extends AccessibleObject implements Member {
* @throws IllegalAccessException
* if this field is not accessible
*/
- public void setDouble(Object object, double value) throws IllegalAccessException,
- IllegalArgumentException {
- setDouble(object, value, isAccessible());
- }
-
- private native void setDouble(Object object, double value, boolean accessible)
+ public native void setDouble(Object object, double value)
throws IllegalAccessException, IllegalArgumentException;
/**
@@ -728,12 +675,7 @@ public final class Field extends AccessibleObject implements Member {
* @throws IllegalAccessException
* if this field is not accessible
*/
- public void setFloat(Object object, float value) throws IllegalAccessException,
- IllegalArgumentException {
- setFloat(object, value, isAccessible());
- }
-
- private native void setFloat(Object object, float value, boolean accessible)
+ public native void setFloat(Object object, float value)
throws IllegalAccessException, IllegalArgumentException;
/**
@@ -763,12 +705,7 @@ public final class Field extends AccessibleObject implements Member {
* @throws IllegalAccessException
* if this field is not accessible
*/
- public void setInt(Object object, int value) throws IllegalAccessException,
- IllegalArgumentException {
- setInt(object, value, isAccessible());
- }
-
- private native void setInt(Object object, int value, boolean accessible)
+ public native void setInt(Object object, int value)
throws IllegalAccessException, IllegalArgumentException;
/**
@@ -798,12 +735,7 @@ public final class Field extends AccessibleObject implements Member {
* @throws IllegalAccessException
* if this field is not accessible
*/
- public void setLong(Object object, long value) throws IllegalAccessException,
- IllegalArgumentException {
- setLong(object, value, isAccessible());
- }
-
- private native void setLong(Object object, long value, boolean accessible)
+ public native void setLong(Object object, long value)
throws IllegalAccessException, IllegalArgumentException;
/**
@@ -833,12 +765,7 @@ public final class Field extends AccessibleObject implements Member {
* @throws IllegalAccessException
* if this field is not accessible
*/
- public void setShort(Object object, short value) throws IllegalAccessException,
- IllegalArgumentException {
- setShort(object, value, isAccessible());
- }
-
- private native void setShort(Object object, short value, boolean accessible)
+ public native void setShort(Object object, short value)
throws IllegalAccessException, IllegalArgumentException;
/**
@@ -861,7 +788,8 @@ public final class Field extends AccessibleObject implements Member {
*/
@Override
public String toString() {
- StringBuilder result = new StringBuilder(Modifier.toString(getModifiers()));
+ StringBuilder result = new StringBuilder(
+ Modifier.getDeclarationFieldModifiers(getModifiers()));
if (result.length() != 0) {
result.append(' ');
}
diff --git a/libart/src/main/java/java/lang/reflect/Method.java b/libart/src/main/java/java/lang/reflect/Method.java
index 058fb96..a07ec6f 100644
--- a/libart/src/main/java/java/lang/reflect/Method.java
+++ b/libart/src/main/java/java/lang/reflect/Method.java
@@ -57,8 +57,7 @@ public final class Method extends AbstractMethod implements GenericDeclaration,
}
int comparison = a.getName().compareTo(b.getName());
if (comparison == 0) {
- comparison = a.artMethod.findOverriddenMethodIfProxy().compareParameters(
- b.getParameterTypes());
+ comparison = a.compareParameters(b.getParameterTypes());
if (comparison == 0) {
// This is necessary for methods that have covariant return types.
Class<?> aReturnType = a.getReturnType();
@@ -77,12 +76,7 @@ public final class Method extends AbstractMethod implements GenericDeclaration,
/**
* @hide
*/
- public Method(ArtMethod artMethod) {
- super(artMethod);
- }
-
- ArtMethod getArtMethod() {
- return artMethod;
+ private Method() {
}
public Annotation[] getAnnotations() {
@@ -136,7 +130,9 @@ public final class Method extends AbstractMethod implements GenericDeclaration,
* @return the name of this method
*/
@Override public String getName() {
- return ArtMethod.getMethodName(artMethod);
+ Dex dex = declaringClassOfOverriddenMethod.getDex();
+ int nameIndex = dex.nameIndexFromMethodIndex(dexMethodIndex);
+ return declaringClassOfOverriddenMethod.getDexCacheString(dex, nameIndex);
}
/**
@@ -171,7 +167,7 @@ public final class Method extends AbstractMethod implements GenericDeclaration,
* @return the parameter types
*/
@Override public Class<?>[] getParameterTypes() {
- return artMethod.findOverriddenMethodIfProxy().getParameterTypes();
+ return super.getParameterTypes();
}
/**
@@ -181,9 +177,13 @@ public final class Method extends AbstractMethod implements GenericDeclaration,
* @return the return type
*/
public Class<?> getReturnType() {
- return artMethod.findOverriddenMethodIfProxy().getReturnType();
+ Dex dex = declaringClassOfOverriddenMethod.getDex();
+ int returnTypeIndex = dex.returnTypeIndexFromMethodIndex(dexMethodIndex);
+ // Note, in the case of a Proxy the dex cache types are equal.
+ return declaringClassOfOverriddenMethod.getDexCacheType(dex, returnTypeIndex);
}
+
/**
* {@inheritDoc}
*
@@ -209,8 +209,7 @@ public final class Method extends AbstractMethod implements GenericDeclaration,
* @hide needed by Proxy
*/
boolean equalNameAndParameters(Method m) {
- return getName().equals(m.getName()) &&
- ArtMethod.equalMethodParameters(artMethod,m.getParameterTypes());
+ return getName().equals(m.getName()) && equalMethodParameters(m.getParameterTypes());
}
/**
@@ -310,7 +309,8 @@ public final class Method extends AbstractMethod implements GenericDeclaration,
* @return an array of arrays of {@code Annotation} instances
*/
public Annotation[][] getParameterAnnotations() {
- return artMethod.findOverriddenMethodIfProxy().getParameterAnnotations();
+ return AnnotationAccess.getParameterAnnotations(
+ declaringClassOfOverriddenMethod, dexMethodIndex);
}
/**
@@ -367,12 +367,7 @@ public final class Method extends AbstractMethod implements GenericDeclaration,
* @throws InvocationTargetException
* if an exception was thrown by the invoked method
*/
- public Object invoke(Object receiver, Object... args)
- throws IllegalAccessException, IllegalArgumentException, InvocationTargetException {
- return invoke(receiver, args, isAccessible());
- }
-
- private native Object invoke(Object receiver, Object[] args, boolean accessible)
+ public native Object invoke(Object receiver, Object... args)
throws IllegalAccessException, IllegalArgumentException, InvocationTargetException;
/**
@@ -398,7 +393,8 @@ public final class Method extends AbstractMethod implements GenericDeclaration,
*/
@Override
public String toString() {
- StringBuilder result = new StringBuilder(Modifier.toString(getModifiers()));
+ StringBuilder result = new StringBuilder(
+ Modifier.getDeclarationMethodModifiers(getModifiers()));
if (result.length() != 0) {
result.append(' ');
diff --git a/libart/src/main/java/java/lang/reflect/Proxy.java b/libart/src/main/java/java/lang/reflect/Proxy.java
index 31f9cd9..18ad49c 100644..100755
--- a/libart/src/main/java/java/lang/reflect/Proxy.java
+++ b/libart/src/main/java/java/lang/reflect/Proxy.java
@@ -166,11 +166,7 @@ public class Proxy implements Serializable {
Collections.sort(methods, ORDER_BY_SIGNATURE_AND_SUBTYPE);
validateReturnTypes(methods);
List<Class<?>[]> exceptions = deduplicateAndGetExceptions(methods);
-
- ArtMethod[] methodsArray = new ArtMethod[methods.size()];
- for (int i = 0; i < methodsArray.length; i++) {
- methodsArray[i] = methods.get(i).getArtMethod();
- }
+ Method[] methodsArray = methods.toArray(new Method[methods.size()]);
Class<?>[][] exceptionsArray = exceptions.toArray(new Class<?>[exceptions.size()][]);
String baseName = commonPackageName != null && !commonPackageName.isEmpty()
@@ -179,7 +175,7 @@ public class Proxy implements Serializable {
Class<?> result;
synchronized (loader.proxyCache) {
- result = loader.proxyCache.get(interfaceSet);
+ result = loader.proxyCache.get(interfaceList);
if (result == null) {
String name = baseName + nextClassNameIndex++;
result = generateProxy(name, interfaces, loader, methodsArray, exceptionsArray);
@@ -383,7 +379,7 @@ public class Proxy implements Serializable {
}
private static native Class<?> generateProxy(String name, Class<?>[] interfaces,
- ClassLoader loader, ArtMethod[] methods,
+ ClassLoader loader, Method[] methods,
Class<?>[][] exceptions);
/*
@@ -392,8 +388,8 @@ public class Proxy implements Serializable {
*/
private static native void constructorPrototype(InvocationHandler h);
- static Object invoke(Proxy proxy, ArtMethod method, Object[] args) throws Throwable {
+ private static Object invoke(Proxy proxy, Method method, Object[] args) throws Throwable {
InvocationHandler h = proxy.h;
- return h.invoke(proxy, new Method(method), args);
+ return h.invoke(proxy, method, args);
}
}
diff --git a/libart/src/main/java/sun/misc/Unsafe.java b/libart/src/main/java/sun/misc/Unsafe.java
index 6f5f5ee..1f938de 100644
--- a/libart/src/main/java/sun/misc/Unsafe.java
+++ b/libart/src/main/java/sun/misc/Unsafe.java
@@ -294,9 +294,9 @@ public final class Unsafe {
*/
public void park(boolean absolute, long time) {
if (absolute) {
- Thread.currentThread().parkUntil(time);
+ Thread.currentThread().parkUntil$(time);
} else {
- Thread.currentThread().parkFor(time);
+ Thread.currentThread().parkFor$(time);
}
}
@@ -310,7 +310,7 @@ public final class Unsafe {
*/
public void unpark(Object obj) {
if (obj instanceof Thread) {
- ((Thread) obj).unpark();
+ ((Thread) obj).unpark$();
} else {
throw new IllegalArgumentException("valid for Threads only");
}
diff --git a/luni/src/benchmark/native/libcore_io_Memory_bench.cpp b/luni/src/benchmark/native/libcore_io_Memory_bench.cpp
new file mode 100644
index 0000000..0819c27
--- /dev/null
+++ b/luni/src/benchmark/native/libcore_io_Memory_bench.cpp
@@ -0,0 +1,105 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// The functions we want to benchmark are static, so include the source code.
+#include "luni/src/main/native/libcore_io_Memory.cpp"
+
+#include <benchmark/Benchmark.h>
+
+template<typename T, size_t ALIGN>
+void swap_bench(testing::Benchmark* bench, void (*swap_func)(T*, const T*, size_t),
+ int iters, size_t num_elements) {
+ T* src;
+ T* dst;
+ T* src_elems;
+ T* dst_elems;
+
+ if (ALIGN) {
+ src_elems = new T[num_elements + 1];
+ dst_elems = new T[num_elements + 1];
+
+ src = reinterpret_cast<T*>(reinterpret_cast<uintptr_t>(src_elems) + ALIGN);
+ dst = reinterpret_cast<T*>(reinterpret_cast<uintptr_t>(dst_elems) + ALIGN);
+ } else {
+ src_elems = new T[num_elements];
+ dst_elems = new T[num_elements];
+
+ src = src_elems;
+ dst = dst_elems;
+ }
+
+ memset(dst, 0, sizeof(T) * num_elements);
+ memset(src, 0x12, sizeof(T) * num_elements);
+
+ bench->StartBenchmarkTiming();
+
+ for (int i = 0; i < iters; i++) {
+ swap_func(src, dst, num_elements);
+ }
+
+ bench->StopBenchmarkTiming();
+
+ delete[] src_elems;
+ delete[] dst_elems;
+}
+
+#define AT_COMMON_VALUES \
+ Arg(10)->Arg(100)->Arg(1000)->Arg(1024*10)->Arg(1024*100)
+
+BENCHMARK_WITH_ARG(BM_libcore_swapShorts_aligned, int)->AT_COMMON_VALUES;
+void BM_libcore_swapShorts_aligned::Run(int iters, int num_shorts) {
+ swap_bench<jshort, 0>(this, swapShorts, iters, num_shorts);
+}
+
+BENCHMARK_WITH_ARG(BM_libcore_swapInts_aligned, int)->AT_COMMON_VALUES;
+void BM_libcore_swapInts_aligned::Run(int iters, int num_ints) {
+ swap_bench<jint, 0>(this, swapInts, iters, num_ints);
+}
+
+BENCHMARK_WITH_ARG(BM_libcore_swapLongs_aligned, int)->AT_COMMON_VALUES;
+void BM_libcore_swapLongs_aligned::Run(int iters, int num_longs) {
+ swap_bench<jlong, 0>(this, swapLongs, iters, num_longs);
+}
+
+BENCHMARK_WITH_ARG(BM_libcore_swapShorts_unaligned1, int)->AT_COMMON_VALUES;
+void BM_libcore_swapShorts_unaligned1::Run(int iters, int num_shorts) {
+ swap_bench<jshort, 1>(this, swapShorts, iters, num_shorts);
+}
+
+BENCHMARK_WITH_ARG(BM_libcore_swapInts_unaligned1, int)->AT_COMMON_VALUES;
+void BM_libcore_swapInts_unaligned1::Run(int iters, int num_ints) {
+ swap_bench<jint, 1>(this, swapInts, iters, num_ints);
+}
+
+BENCHMARK_WITH_ARG(BM_libcore_swapLongs_unaligned1, int)->AT_COMMON_VALUES;
+void BM_libcore_swapLongs_unaligned1::Run(int iters, int num_longs) {
+ swap_bench<jlong, 1>(this, swapLongs, iters, num_longs);
+}
+
+BENCHMARK_WITH_ARG(BM_libcore_swapShorts_unaligned2, int)->AT_COMMON_VALUES;
+void BM_libcore_swapShorts_unaligned2::Run(int iters, int num_shorts) {
+ swap_bench<jshort, 2>(this, swapShorts, iters, num_shorts);
+}
+
+BENCHMARK_WITH_ARG(BM_libcore_swapInts_unaligned2, int)->AT_COMMON_VALUES;
+void BM_libcore_swapInts_unaligned2::Run(int iters, int num_ints) {
+ swap_bench<jint, 2>(this, swapInts, iters, num_ints);
+}
+
+BENCHMARK_WITH_ARG(BM_libcore_swapLongs_unaligned2, int)->AT_COMMON_VALUES;
+void BM_libcore_swapLongs_unaligned2::Run(int iters, int num_longs) {
+ swap_bench<jlong, 2>(this, swapLongs, iters, num_longs);
+}
diff --git a/luni/src/main/files/README.cacerts b/luni/src/main/files/README.cacerts
index e905a68..ca5c570 100755
--- a/luni/src/main/files/README.cacerts
+++ b/luni/src/main/files/README.cacerts
@@ -1,7 +1,7 @@
The filenames in the cacerts directory are in the format of <hash>.<n>
where "hash" is the subject hash produced by:
- openssl x509 -subject_hash -in filename
+ openssl x509 -subject_hash_old -in filename
and the "n" is a unique integer identifier starting at 0 to deal
with collisions. See OpenSSL's c_rehash manpage for details.
diff --git a/luni/src/main/files/cacerts/0d188d89.0 b/luni/src/main/files/cacerts/0d188d89.0
deleted file mode 100644
index 07a14ef..0000000
--- a/luni/src/main/files/cacerts/0d188d89.0
+++ /dev/null
@@ -1,80 +0,0 @@
------BEGIN CERTIFICATE-----
-MIIDtjCCAp6gAwIBAgIQRJmNPMADJ72cdpW56tustTANBgkqhkiG9w0BAQUFADB1
-MQswCQYDVQQGEwJUUjEoMCYGA1UEChMfRWxla3Ryb25payBCaWxnaSBHdXZlbmxp
-Z2kgQS5TLjE8MDoGA1UEAxMzZS1HdXZlbiBLb2sgRWxla3Ryb25payBTZXJ0aWZp
-a2EgSGl6bWV0IFNhZ2xheWljaXNpMB4XDTA3MDEwNDExMzI0OFoXDTE3MDEwNDEx
-MzI0OFowdTELMAkGA1UEBhMCVFIxKDAmBgNVBAoTH0VsZWt0cm9uaWsgQmlsZ2kg
-R3V2ZW5saWdpIEEuUy4xPDA6BgNVBAMTM2UtR3V2ZW4gS29rIEVsZWt0cm9uaWsg
-U2VydGlmaWthIEhpem1ldCBTYWdsYXlpY2lzaTCCASIwDQYJKoZIhvcNAQEBBQAD
-ggEPADCCAQoCggEBAMMSIJ6wXgBljU5Gu4Bc6SwGl9XzcslwuedLZYDBS75+PNdU
-MZTe1RK6UxYC6lhj71vY8+0qGqpxSKPcEC1fX+tcS5yWCEIlKBHMilpiAVDV6wlT
-L/jDj/6z/P2douNffb7tC+Bg62nsM+3YjfsSSYMAyYuXjDtzKjKzEve5TfL0TW3H
-5tYmNwjy2f1rXKPlSFxYvEK+A1qBuhw1DADT9SN+cTAIJjjcJRFHLfO6IxClv7wC
-90Nex/6wN1CZew+TzuZDLMN+DfIcQ2Zgy2ExR4ejT669VmxMvLz4Bcpk9Ok0oSy1
-c+HCPujIyTQlCFzz7abHlJ+tiEMl1+E5YP6sOVkCAwEAAaNCMEAwDgYDVR0PAQH/
-BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFJ/uRLOU1fqRTy7ZVZoE
-VtstxNulMA0GCSqGSIb3DQEBBQUAA4IBAQB/X7lTW2M9dTLn+sR0GstG30ZpHFLP
-qk/CaOv/gKlR6D1id4k9CnU58W5dF4dvaAXBlGzZXd/aslnLpRCKysw5zZ/rTt5S
-/wzw9JKp8mxTq5vSR6AfdPebmvEvFZ96ZDAYBzwqD2fK/A+JYZ1lpTzlvBNbCNvj
-/+27BrtqBrF6T2XGgv0enIu1De5Iu7i9qgi0+6N8y5/NkHZchpZ4Vwpm+Vganf2X
-KWDeEaaQHBkc7gGWIjQ0LpH5t8Qn0Xvmv/uARFoW5evg1Ao4vOSR49XrXMGs3xtq
-fJ7lddK2l4fbzIcrQzqECK+rPNv3PGYxhrCdU3nt+CPeQuMtgvEP5fqX
------END CERTIFICATE-----
-Certificate:
- Data:
- Version: 3 (0x2)
- Serial Number:
- 44:99:8d:3c:c0:03:27:bd:9c:76:95:b9:ea:db:ac:b5
- Signature Algorithm: sha1WithRSAEncryption
- Issuer: C=TR, O=Elektronik Bilgi Guvenligi A.S., CN=e-Guven Kok Elektronik Sertifika Hizmet Saglayicisi
- Validity
- Not Before: Jan 4 11:32:48 2007 GMT
- Not After : Jan 4 11:32:48 2017 GMT
- Subject: C=TR, O=Elektronik Bilgi Guvenligi A.S., CN=e-Guven Kok Elektronik Sertifika Hizmet Saglayicisi
- Subject Public Key Info:
- Public Key Algorithm: rsaEncryption
- Public-Key: (2048 bit)
- Modulus:
- 00:c3:12:20:9e:b0:5e:00:65:8d:4e:46:bb:80:5c:
- e9:2c:06:97:d5:f3:72:c9:70:b9:e7:4b:65:80:c1:
- 4b:be:7e:3c:d7:54:31:94:de:d5:12:ba:53:16:02:
- ea:58:63:ef:5b:d8:f3:ed:2a:1a:aa:71:48:a3:dc:
- 10:2d:5f:5f:eb:5c:4b:9c:96:08:42:25:28:11:cc:
- 8a:5a:62:01:50:d5:eb:09:53:2f:f8:c3:8f:fe:b3:
- fc:fd:9d:a2:e3:5f:7d:be:ed:0b:e0:60:eb:69:ec:
- 33:ed:d8:8d:fb:12:49:83:00:c9:8b:97:8c:3b:73:
- 2a:32:b3:12:f7:b9:4d:f2:f4:4d:6d:c7:e6:d6:26:
- 37:08:f2:d9:fd:6b:5c:a3:e5:48:5c:58:bc:42:be:
- 03:5a:81:ba:1c:35:0c:00:d3:f5:23:7e:71:30:08:
- 26:38:dc:25:11:47:2d:f3:ba:23:10:a5:bf:bc:02:
- f7:43:5e:c7:fe:b0:37:50:99:7b:0f:93:ce:e6:43:
- 2c:c3:7e:0d:f2:1c:43:66:60:cb:61:31:47:87:a3:
- 4f:ae:bd:56:6c:4c:bc:bc:f8:05:ca:64:f4:e9:34:
- a1:2c:b5:73:e1:c2:3e:e8:c8:c9:34:25:08:5c:f3:
- ed:a6:c7:94:9f:ad:88:43:25:d7:e1:39:60:fe:ac:
- 39:59
- Exponent: 65537 (0x10001)
- X509v3 extensions:
- X509v3 Key Usage: critical
- Certificate Sign, CRL Sign
- X509v3 Basic Constraints: critical
- CA:TRUE
- X509v3 Subject Key Identifier:
- 9F:EE:44:B3:94:D5:FA:91:4F:2E:D9:55:9A:04:56:DB:2D:C4:DB:A5
- Signature Algorithm: sha1WithRSAEncryption
- 7f:5f:b9:53:5b:63:3d:75:32:e7:fa:c4:74:1a:cb:46:df:46:
- 69:1c:52:cf:aa:4f:c2:68:eb:ff:80:a9:51:e8:3d:62:77:89:
- 3d:0a:75:39:f1:6e:5d:17:87:6f:68:05:c1:94:6c:d9:5d:df:
- da:b2:59:cb:a5:10:8a:ca:cc:39:cd:9f:eb:4e:de:52:ff:0c:
- f0:f4:92:a9:f2:6c:53:ab:9b:d2:47:a0:1f:74:f7:9b:9a:f1:
- 2f:15:9f:7a:64:30:18:07:3c:2a:0f:67:ca:fc:0f:89:61:9d:
- 65:a5:3c:e5:bc:13:5b:08:db:e3:ff:ed:bb:06:bb:6a:06:b1:
- 7a:4f:65:c6:82:fd:1e:9c:8b:b5:0d:ee:48:bb:b8:bd:aa:08:
- b4:fb:a3:7c:cb:9f:cd:90:76:5c:86:96:78:57:0a:66:f9:58:
- 1a:9d:fd:97:29:60:de:11:a6:90:1c:19:1c:ee:01:96:22:34:
- 34:2e:91:f9:b7:c4:27:d1:7b:e6:bf:fb:80:44:5a:16:e5:eb:
- e0:d4:0a:38:bc:e4:91:e3:d5:eb:5c:c1:ac:df:1b:6a:7c:9e:
- e5:75:d2:b6:97:87:db:cc:87:2b:43:3a:84:08:af:ab:3c:db:
- f7:3c:66:31:86:b0:9d:53:79:ed:f8:23:de:42:e3:2d:82:f1:
- 0f:e5:fa:97
-SHA1 Fingerprint=DD:E1:D2:A9:01:80:2E:1D:87:5E:84:B3:80:7E:4B:B1:FD:99:41:34
diff --git a/luni/src/main/files/cacerts/0d5a4e1c.0 b/luni/src/main/files/cacerts/0d5a4e1c.0
new file mode 100644
index 0000000..2a40cf6
--- /dev/null
+++ b/luni/src/main/files/cacerts/0d5a4e1c.0
@@ -0,0 +1,82 @@
+-----BEGIN CERTIFICATE-----
+MIIEJzCCAw+gAwIBAgIHAI4X/iQggTANBgkqhkiG9w0BAQsFADCBsTELMAkGA1UE
+BhMCVFIxDzANBgNVBAcMBkFua2FyYTFNMEsGA1UECgxEVMOcUktUUlVTVCBCaWxn
+aSDEsGxldGnFn2ltIHZlIEJpbGnFn2ltIEfDvHZlbmxpxJ9pIEhpem1ldGxlcmkg
+QS7Fni4xQjBABgNVBAMMOVTDnFJLVFJVU1QgRWxla3Ryb25payBTZXJ0aWZpa2Eg
+SGl6bWV0IFNhxJ9sYXnEsWPEsXPEsSBINTAeFw0xMzA0MzAwODA3MDFaFw0yMzA0
+MjgwODA3MDFaMIGxMQswCQYDVQQGEwJUUjEPMA0GA1UEBwwGQW5rYXJhMU0wSwYD
+VQQKDERUw5xSS1RSVVNUIEJpbGdpIMSwbGV0acWfaW0gdmUgQmlsacWfaW0gR8O8
+dmVubGnEn2kgSGl6bWV0bGVyaSBBLsWeLjFCMEAGA1UEAww5VMOcUktUUlVTVCBF
+bGVrdHJvbmlrIFNlcnRpZmlrYSBIaXptZXQgU2HEn2xhecSxY8Sxc8SxIEg1MIIB
+IjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEApCUZ4WWe60ghUEoI5RHwWrom
+/4NZzkQqL/7hzmAD/I0Dpe3/a6i6zDQGn1k19uwsu537jVJp45wnEFPzpALFp/kR
+Gml1bsMdi9GYjZOHp3GXDSHHmflS0yxjXVW86B8BSLlg/kJK9siArs1mep5Fimh3
+4khon6La8eHBEJ/rPCmBp+EyCNSgBbGM+42WAA4+Jd9ThiI7/PS98wl+d+yG6w8z
+5UNP9FR1bSmZLmZaQ9/LXMrI5Tjxfjs1nQ/0xVqhzPMggCTTV+wVunUlm+hkS7M0
+hO8EuPbJbKoCPrZV4jI3X/xml1/N1p7HIL9Nxqw/dV8c7TKcfGkAaZHjIxhT6QID
+AQABo0IwQDAdBgNVHQ4EFgQUVpkHHtOsDGlktAxQR95DLL4gwPswDgYDVR0PAQH/
+BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBAJ5FdnsX
+SDLyOIspve6WSk6BGLFRRyDN0GSxDsnZAdkJzsiZ3GglE9Rc8qPoBP5yCccLqh0l
+VX6Wmle3usURehnmp349hQ71+S4pL+f5bFgWV1Al9j4uPqrtd3GqqpmWRgqujuwq
+URawXs3qZwQcWDD1YIq9pr1N5Za0/EKJAWv2cMhQOQwt1WbZyNKzMrcbGW3LM/nf
+peYVhDfwwvJllpKQd/Ct9JDpEXjXk4nAPQu6KfTomZ1yju2dL+6SfaHx/126M2CF
+Yv4HAqGEVka+lgqaE9chTLd8B59OTj+RdPsnnRHM3eaxynFNExc5JsUpISuTKWqW
++qtB4Uu2NQvAmxU=
+-----END CERTIFICATE-----
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number: 156233699172481 (0x8e17fe242081)
+ Signature Algorithm: sha256WithRSAEncryption
+ Issuer: C=TR, L=Ankara, O=T\xC3\x9CRKTRUST Bilgi \xC4\xB0leti\xC5\x9Fim ve Bili\xC5\x9Fim G\xC3\xBCvenli\xC4\x9Fi Hizmetleri A.\xC5\x9E., CN=T\xC3\x9CRKTRUST Elektronik Sertifika Hizmet Sa\xC4\x9Flay\xC4\xB1c\xC4\xB1s\xC4\xB1 H5
+ Validity
+ Not Before: Apr 30 08:07:01 2013 GMT
+ Not After : Apr 28 08:07:01 2023 GMT
+ Subject: C=TR, L=Ankara, O=T\xC3\x9CRKTRUST Bilgi \xC4\xB0leti\xC5\x9Fim ve Bili\xC5\x9Fim G\xC3\xBCvenli\xC4\x9Fi Hizmetleri A.\xC5\x9E., CN=T\xC3\x9CRKTRUST Elektronik Sertifika Hizmet Sa\xC4\x9Flay\xC4\xB1c\xC4\xB1s\xC4\xB1 H5
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ Public-Key: (2048 bit)
+ Modulus:
+ 00:a4:25:19:e1:65:9e:eb:48:21:50:4a:08:e5:11:
+ f0:5a:ba:26:ff:83:59:ce:44:2a:2f:fe:e1:ce:60:
+ 03:fc:8d:03:a5:ed:ff:6b:a8:ba:cc:34:06:9f:59:
+ 35:f6:ec:2c:bb:9d:fb:8d:52:69:e3:9c:27:10:53:
+ f3:a4:02:c5:a7:f9:11:1a:69:75:6e:c3:1d:8b:d1:
+ 98:8d:93:87:a7:71:97:0d:21:c7:99:f9:52:d3:2c:
+ 63:5d:55:bc:e8:1f:01:48:b9:60:fe:42:4a:f6:c8:
+ 80:ae:cd:66:7a:9e:45:8a:68:77:e2:48:68:9f:a2:
+ da:f1:e1:c1:10:9f:eb:3c:29:81:a7:e1:32:08:d4:
+ a0:05:b1:8c:fb:8d:96:00:0e:3e:25:df:53:86:22:
+ 3b:fc:f4:bd:f3:09:7e:77:ec:86:eb:0f:33:e5:43:
+ 4f:f4:54:75:6d:29:99:2e:66:5a:43:df:cb:5c:ca:
+ c8:e5:38:f1:7e:3b:35:9d:0f:f4:c5:5a:a1:cc:f3:
+ 20:80:24:d3:57:ec:15:ba:75:25:9b:e8:64:4b:b3:
+ 34:84:ef:04:b8:f6:c9:6c:aa:02:3e:b6:55:e2:32:
+ 37:5f:fc:66:97:5f:cd:d6:9e:c7:20:bf:4d:c6:ac:
+ 3f:75:5f:1c:ed:32:9c:7c:69:00:69:91:e3:23:18:
+ 53:e9
+ Exponent: 65537 (0x10001)
+ X509v3 extensions:
+ X509v3 Subject Key Identifier:
+ 56:99:07:1E:D3:AC:0C:69:64:B4:0C:50:47:DE:43:2C:BE:20:C0:FB
+ X509v3 Key Usage: critical
+ Certificate Sign, CRL Sign
+ X509v3 Basic Constraints: critical
+ CA:TRUE
+ Signature Algorithm: sha256WithRSAEncryption
+ 9e:45:76:7b:17:48:32:f2:38:8b:29:bd:ee:96:4a:4e:81:18:
+ b1:51:47:20:cd:d0:64:b1:0e:c9:d9:01:d9:09:ce:c8:99:dc:
+ 68:25:13:d4:5c:f2:a3:e8:04:fe:72:09:c7:0b:aa:1d:25:55:
+ 7e:96:9a:57:b7:ba:c5:11:7a:19:e6:a7:7e:3d:85:0e:f5:f9:
+ 2e:29:2f:e7:f9:6c:58:16:57:50:25:f6:3e:2e:3e:aa:ed:77:
+ 71:aa:aa:99:96:46:0a:ae:8e:ec:2a:51:16:b0:5e:cd:ea:67:
+ 04:1c:58:30:f5:60:8a:bd:a6:bd:4d:e5:96:b4:fc:42:89:01:
+ 6b:f6:70:c8:50:39:0c:2d:d5:66:d9:c8:d2:b3:32:b7:1b:19:
+ 6d:cb:33:f9:df:a5:e6:15:84:37:f0:c2:f2:65:96:92:90:77:
+ f0:ad:f4:90:e9:11:78:d7:93:89:c0:3d:0b:ba:29:f4:e8:99:
+ 9d:72:8e:ed:9d:2f:ee:92:7d:a1:f1:ff:5d:ba:33:60:85:62:
+ fe:07:02:a1:84:56:46:be:96:0a:9a:13:d7:21:4c:b7:7c:07:
+ 9f:4e:4e:3f:91:74:fb:27:9d:11:cc:dd:e6:b1:ca:71:4d:13:
+ 17:39:26:c5:29:21:2b:93:29:6a:96:fa:ab:41:e1:4b:b6:35:
+ 0b:c0:9b:15
+SHA1 Fingerprint=C4:18:F6:4D:46:D1:DF:00:3D:27:30:13:72:43:A9:12:11:C6:75:FB
diff --git a/luni/src/main/files/cacerts/2afc57aa.0 b/luni/src/main/files/cacerts/2afc57aa.0
deleted file mode 100644
index aefb4ad..0000000
--- a/luni/src/main/files/cacerts/2afc57aa.0
+++ /dev/null
@@ -1,91 +0,0 @@
------BEGIN CERTIFICATE-----
-MIIEqjCCA5KgAwIBAgIOLmoAAQACH9dSISwRXDswDQYJKoZIhvcNAQEFBQAwdjEL
-MAkGA1UEBhMCREUxHDAaBgNVBAoTE1RDIFRydXN0Q2VudGVyIEdtYkgxIjAgBgNV
-BAsTGVRDIFRydXN0Q2VudGVyIENsYXNzIDIgQ0ExJTAjBgNVBAMTHFRDIFRydXN0
-Q2VudGVyIENsYXNzIDIgQ0EgSUkwHhcNMDYwMTEyMTQzODQzWhcNMjUxMjMxMjI1
-OTU5WjB2MQswCQYDVQQGEwJERTEcMBoGA1UEChMTVEMgVHJ1c3RDZW50ZXIgR21i
-SDEiMCAGA1UECxMZVEMgVHJ1c3RDZW50ZXIgQ2xhc3MgMiBDQTElMCMGA1UEAxMc
-VEMgVHJ1c3RDZW50ZXIgQ2xhc3MgMiBDQSBJSTCCASIwDQYJKoZIhvcNAQEBBQAD
-ggEPADCCAQoCggEBAKuAh5uO8MN8h9foJIIRszzdQ2Lu+MNF2ujhoF/RKrLqk2jf
-tMjWQ+nEdVl//OEd+DFwIxuInie5e/060smp6RQvkL4DUsFJzfb95AhmC1eKokKg
-uNV/aVyQMrKXDcpK3EY+AlWJU+MaWss2xgdW94zPEfRMuzBwBJWl9jmM/XOBCH2J
-XjIeIqkiRUuwZi4wzJ9l/fzLganx4Duvo4bRierERXlQXa7pIXSSTYtZgo+U4+lK
-8edJsBTj9WLL1XK9H7nSn6DNqPoByNkN39r8R52zyFTfSUrxIan+GE7uSNQZu+99
-5OKdy1u2bv/jzVrndIIFuoAlOMvkaZ6vQaoahPUCAwEAAaOCATQwggEwMA8GA1Ud
-EwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBTjq1RMgKHbVkO3
-kUrL84J6E1wIqzCB7QYDVR0fBIHlMIHiMIHfoIHcoIHZhjVodHRwOi8vd3d3LnRy
-dXN0Y2VudGVyLmRlL2NybC92Mi90Y19jbGFzc18yX2NhX0lJLmNybIaBn2xkYXA6
-Ly93d3cudHJ1c3RjZW50ZXIuZGUvQ049VEMlMjBUcnVzdENlbnRlciUyMENsYXNz
-JTIwMiUyMENBJTIwSUksTz1UQyUyMFRydXN0Q2VudGVyJTIwR21iSCxPVT1yb290
-Y2VydHMsREM9dHJ1c3RjZW50ZXIsREM9ZGU/Y2VydGlmaWNhdGVSZXZvY2F0aW9u
-TGlzdD9iYXNlPzANBgkqhkiG9w0BAQUFAAOCAQEAjNfffu4bgBCzg/XbEeprS6iS
-GNn3Bzn1LL4GdXpoUxUc6krtXvwjshOg0wn/9vYua0Fxec3ibf2uWWuFHbhOIprt
-ZjluS5TmVfwLG4t3wVMTZonZKNaL80VKY7f9ewthXbhtvsPcW3nS7Yblok2+XnR8
-au0WOB9/WIFaGusyiC2y8zl3gK9etmF1KdsjTYjKUCjLhdLTEKJZbtOTVAB6okaV
-hgWcqRmY5TFyDADiZ9lA4CQze28suVyrZZ0srHbqNZn1l7kPJOzHdiEoZa5X6AeI
-dUpWoNIFOqTmjZKILPPy4cHGYdtBxceb9w4aUUXCYWvcZCcXjFq32nQozZfkvQ==
------END CERTIFICATE-----
-Certificate:
- Data:
- Version: 3 (0x2)
- Serial Number:
- 2e:6a:00:01:00:02:1f:d7:52:21:2c:11:5c:3b
- Signature Algorithm: sha1WithRSAEncryption
- Issuer: C=DE, O=TC TrustCenter GmbH, OU=TC TrustCenter Class 2 CA, CN=TC TrustCenter Class 2 CA II
- Validity
- Not Before: Jan 12 14:38:43 2006 GMT
- Not After : Dec 31 22:59:59 2025 GMT
- Subject: C=DE, O=TC TrustCenter GmbH, OU=TC TrustCenter Class 2 CA, CN=TC TrustCenter Class 2 CA II
- Subject Public Key Info:
- Public Key Algorithm: rsaEncryption
- Public-Key: (2048 bit)
- Modulus:
- 00:ab:80:87:9b:8e:f0:c3:7c:87:d7:e8:24:82:11:
- b3:3c:dd:43:62:ee:f8:c3:45:da:e8:e1:a0:5f:d1:
- 2a:b2:ea:93:68:df:b4:c8:d6:43:e9:c4:75:59:7f:
- fc:e1:1d:f8:31:70:23:1b:88:9e:27:b9:7b:fd:3a:
- d2:c9:a9:e9:14:2f:90:be:03:52:c1:49:cd:f6:fd:
- e4:08:66:0b:57:8a:a2:42:a0:b8:d5:7f:69:5c:90:
- 32:b2:97:0d:ca:4a:dc:46:3e:02:55:89:53:e3:1a:
- 5a:cb:36:c6:07:56:f7:8c:cf:11:f4:4c:bb:30:70:
- 04:95:a5:f6:39:8c:fd:73:81:08:7d:89:5e:32:1e:
- 22:a9:22:45:4b:b0:66:2e:30:cc:9f:65:fd:fc:cb:
- 81:a9:f1:e0:3b:af:a3:86:d1:89:ea:c4:45:79:50:
- 5d:ae:e9:21:74:92:4d:8b:59:82:8f:94:e3:e9:4a:
- f1:e7:49:b0:14:e3:f5:62:cb:d5:72:bd:1f:b9:d2:
- 9f:a0:cd:a8:fa:01:c8:d9:0d:df:da:fc:47:9d:b3:
- c8:54:df:49:4a:f1:21:a9:fe:18:4e:ee:48:d4:19:
- bb:ef:7d:e4:e2:9d:cb:5b:b6:6e:ff:e3:cd:5a:e7:
- 74:82:05:ba:80:25:38:cb:e4:69:9e:af:41:aa:1a:
- 84:f5
- Exponent: 65537 (0x10001)
- X509v3 extensions:
- X509v3 Basic Constraints: critical
- CA:TRUE
- X509v3 Key Usage: critical
- Certificate Sign, CRL Sign
- X509v3 Subject Key Identifier:
- E3:AB:54:4C:80:A1:DB:56:43:B7:91:4A:CB:F3:82:7A:13:5C:08:AB
- X509v3 CRL Distribution Points:
-
- Full Name:
- URI:http://www.trustcenter.de/crl/v2/tc_class_2_ca_II.crl
- URI:ldap://www.trustcenter.de/CN=TC%20TrustCenter%20Class%202%20CA%20II,O=TC%20TrustCenter%20GmbH,OU=rootcerts,DC=trustcenter,DC=de?certificateRevocationList?base?
-
- Signature Algorithm: sha1WithRSAEncryption
- 8c:d7:df:7e:ee:1b:80:10:b3:83:f5:db:11:ea:6b:4b:a8:92:
- 18:d9:f7:07:39:f5:2c:be:06:75:7a:68:53:15:1c:ea:4a:ed:
- 5e:fc:23:b2:13:a0:d3:09:ff:f6:f6:2e:6b:41:71:79:cd:e2:
- 6d:fd:ae:59:6b:85:1d:b8:4e:22:9a:ed:66:39:6e:4b:94:e6:
- 55:fc:0b:1b:8b:77:c1:53:13:66:89:d9:28:d6:8b:f3:45:4a:
- 63:b7:fd:7b:0b:61:5d:b8:6d:be:c3:dc:5b:79:d2:ed:86:e5:
- a2:4d:be:5e:74:7c:6a:ed:16:38:1f:7f:58:81:5a:1a:eb:32:
- 88:2d:b2:f3:39:77:80:af:5e:b6:61:75:29:db:23:4d:88:ca:
- 50:28:cb:85:d2:d3:10:a2:59:6e:d3:93:54:00:7a:a2:46:95:
- 86:05:9c:a9:19:98:e5:31:72:0c:00:e2:67:d9:40:e0:24:33:
- 7b:6f:2c:b9:5c:ab:65:9d:2c:ac:76:ea:35:99:f5:97:b9:0f:
- 24:ec:c7:76:21:28:65:ae:57:e8:07:88:75:4a:56:a0:d2:05:
- 3a:a4:e6:8d:92:88:2c:f3:f2:e1:c1:c6:61:db:41:c5:c7:9b:
- f7:0e:1a:51:45:c2:61:6b:dc:64:27:17:8c:5a:b7:da:74:28:
- cd:97:e4:bd
-SHA1 Fingerprint=AE:50:83:ED:7C:F4:5C:BC:8F:61:C6:21:FE:68:5D:79:42:21:15:6E
diff --git a/luni/src/main/files/cacerts/2fb1850a.0 b/luni/src/main/files/cacerts/2fb1850a.0
deleted file mode 100644
index 20dd1ee..0000000
--- a/luni/src/main/files/cacerts/2fb1850a.0
+++ /dev/null
@@ -1,124 +0,0 @@
------BEGIN CERTIFICATE-----
-MIIFpDCCA4ygAwIBAgIBATANBgkqhkiG9w0BAQUFADBjMQswCQYDVQQGEwJVUzEc
-MBoGA1UEChMTQW1lcmljYSBPbmxpbmUgSW5jLjE2MDQGA1UEAxMtQW1lcmljYSBP
-bmxpbmUgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAyMB4XDTAyMDUyODA2
-MDAwMFoXDTM3MDkyOTE0MDgwMFowYzELMAkGA1UEBhMCVVMxHDAaBgNVBAoTE0Ft
-ZXJpY2EgT25saW5lIEluYy4xNjA0BgNVBAMTLUFtZXJpY2EgT25saW5lIFJvb3Qg
-Q2VydGlmaWNhdGlvbiBBdXRob3JpdHkgMjCCAiIwDQYJKoZIhvcNAQEBBQADggIP
-ADCCAgoCggIBAMxBRR3pPU0Q9oyxQcngXssNt79Hc9PwVU3dxgz6sWYFas14tNwC
-206B89enfHG8dWOgXeMHDEjsJcQDIPT/DjsS/5uN4cbVG7RtIuOx238hZK+GvFci
-KtZHgVdEglZTvYYUAQv8f3SkWq7xuhG1m1hagLQ3eAkzfDJHA1zEpYNI9FdWboE2
-JxhP7JsowtS013wMPgwr38oE18aO6lhOqKSlGBxsRZijQdEt0sdtjRnxrXm3gT+9
-BoInLRBYBbV4Bbkv2wxrkJB+FFk4u5QkE+XRnRTf04JNRvCAOVIyD+OEsnpD8l7e
-Xz8d3eOyG6ChKiMDbi4BFYdcpnV1x5dhvt6G3NRI270qv0pV2uh9UPu0gBe4lL8B
-PeraunzgWGcXuVjgiIZGZ2ydEEdYMtA1fHkqkKJaEBEjNa0vzORKW6fIJ/KD3l67
-Xnfn6KVuY8INXWHQjNJsWiEOyiijzirplcdIz5ZvHZIlyMbGwcEMBawmxNJ10uEq
-Z8A9W6Wa6897GqidFEXlD6CaZd4vKL3Ob5Rmg0gp2OpljK+T2WSfVVcmv2/LNzGZ
-o2C7HK2JNDJiuEMhBnIMoVxtRsX6Kc8w3onccVvdtjc+31D1uAclJuW8tf48ArO3
-+L5DwYcRlJ4jbBeKuIonDFRH8KmzwICMoCfrHRnjB453cMor9H124HhnAgMBAAGj
-YzBhMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFE1FwWg4u3OpaaEg5+31IqEj
-FNeeMB8GA1UdIwQYMBaAFE1FwWg4u3OpaaEg5+31IqEjFNeeMA4GA1UdDwEB/wQE
-AwIBhjANBgkqhkiG9w0BAQUFAAOCAgEAZ2sGuV9FOypLM7PmG2tZTiLMubekJcmn
-xPBUlgtk87FYT15R/LKXeydlwuXK5w0MJXti4/qftIe3RUavg6WXSIylvfEWK5t2
-LHo1YGwRgJfMqZJS5ivmae2p+DYtLHe/YUjRYwu5W1LtGLBDQiKmsXeu3mnFzccc
-obGlHBD7GL4acN3Bkku+KVqdPzW+5X1R+FXgJXUjhx5c3LqdsKyzadsXg8n33gy8
-CNyRnqjQ1xU3c6U1uPx+xURABsPr+CKAXEfOAuMRn0T//ZoyzH1kUQ7rVyZ2OuMe
-IjzCpjbdGe+n/BLzJsBZMYVMnNjP36TMzCmT/5RtdlwTCJfy7aULTd3oyWgOZtMA
-DjMSW7yV5TKQqLPGbIOtd+6Lfn6xqavT4fG2wLHqiMDn05DpKJKUe2h7lyoKZy2F
-AjgQ5ANh1NolNscIWC2hp1GvMApJ9aZphwctREZ2jirlmjvXGKL8nDgQzMY70rUX
-Om/9riW99XJZZLF0KjhfGEzfz3EEWjbUvy+ZnOjZurGV5gJLIaFb1cFPj65pbVPb
-AZO1XB4Y3WRayhgoPmMEEf0cjQAPuDffZ4qdZqkCapH/E8ovXYO8h5Ns3CRRFgQl
-Zvqz2cK6Kb6aSDiCmfS/O0oxGfm/jiEzFMpPVF/7zvuPcX/9XhmgD0uRuMRUvAaw
-RY8mkaKO/qk=
------END CERTIFICATE-----
-Certificate:
- Data:
- Version: 3 (0x2)
- Serial Number: 1 (0x1)
- Signature Algorithm: sha1WithRSAEncryption
- Issuer: C=US, O=America Online Inc., CN=America Online Root Certification Authority 2
- Validity
- Not Before: May 28 06:00:00 2002 GMT
- Not After : Sep 29 14:08:00 2037 GMT
- Subject: C=US, O=America Online Inc., CN=America Online Root Certification Authority 2
- Subject Public Key Info:
- Public Key Algorithm: rsaEncryption
- Public-Key: (4096 bit)
- Modulus:
- 00:cc:41:45:1d:e9:3d:4d:10:f6:8c:b1:41:c9:e0:
- 5e:cb:0d:b7:bf:47:73:d3:f0:55:4d:dd:c6:0c:fa:
- b1:66:05:6a:cd:78:b4:dc:02:db:4e:81:f3:d7:a7:
- 7c:71:bc:75:63:a0:5d:e3:07:0c:48:ec:25:c4:03:
- 20:f4:ff:0e:3b:12:ff:9b:8d:e1:c6:d5:1b:b4:6d:
- 22:e3:b1:db:7f:21:64:af:86:bc:57:22:2a:d6:47:
- 81:57:44:82:56:53:bd:86:14:01:0b:fc:7f:74:a4:
- 5a:ae:f1:ba:11:b5:9b:58:5a:80:b4:37:78:09:33:
- 7c:32:47:03:5c:c4:a5:83:48:f4:57:56:6e:81:36:
- 27:18:4f:ec:9b:28:c2:d4:b4:d7:7c:0c:3e:0c:2b:
- df:ca:04:d7:c6:8e:ea:58:4e:a8:a4:a5:18:1c:6c:
- 45:98:a3:41:d1:2d:d2:c7:6d:8d:19:f1:ad:79:b7:
- 81:3f:bd:06:82:27:2d:10:58:05:b5:78:05:b9:2f:
- db:0c:6b:90:90:7e:14:59:38:bb:94:24:13:e5:d1:
- 9d:14:df:d3:82:4d:46:f0:80:39:52:32:0f:e3:84:
- b2:7a:43:f2:5e:de:5f:3f:1d:dd:e3:b2:1b:a0:a1:
- 2a:23:03:6e:2e:01:15:87:5c:a6:75:75:c7:97:61:
- be:de:86:dc:d4:48:db:bd:2a:bf:4a:55:da:e8:7d:
- 50:fb:b4:80:17:b8:94:bf:01:3d:ea:da:ba:7c:e0:
- 58:67:17:b9:58:e0:88:86:46:67:6c:9d:10:47:58:
- 32:d0:35:7c:79:2a:90:a2:5a:10:11:23:35:ad:2f:
- cc:e4:4a:5b:a7:c8:27:f2:83:de:5e:bb:5e:77:e7:
- e8:a5:6e:63:c2:0d:5d:61:d0:8c:d2:6c:5a:21:0e:
- ca:28:a3:ce:2a:e9:95:c7:48:cf:96:6f:1d:92:25:
- c8:c6:c6:c1:c1:0c:05:ac:26:c4:d2:75:d2:e1:2a:
- 67:c0:3d:5b:a5:9a:eb:cf:7b:1a:a8:9d:14:45:e5:
- 0f:a0:9a:65:de:2f:28:bd:ce:6f:94:66:83:48:29:
- d8:ea:65:8c:af:93:d9:64:9f:55:57:26:bf:6f:cb:
- 37:31:99:a3:60:bb:1c:ad:89:34:32:62:b8:43:21:
- 06:72:0c:a1:5c:6d:46:c5:fa:29:cf:30:de:89:dc:
- 71:5b:dd:b6:37:3e:df:50:f5:b8:07:25:26:e5:bc:
- b5:fe:3c:02:b3:b7:f8:be:43:c1:87:11:94:9e:23:
- 6c:17:8a:b8:8a:27:0c:54:47:f0:a9:b3:c0:80:8c:
- a0:27:eb:1d:19:e3:07:8e:77:70:ca:2b:f4:7d:76:
- e0:78:67
- Exponent: 65537 (0x10001)
- X509v3 extensions:
- X509v3 Basic Constraints: critical
- CA:TRUE
- X509v3 Subject Key Identifier:
- 4D:45:C1:68:38:BB:73:A9:69:A1:20:E7:ED:F5:22:A1:23:14:D7:9E
- X509v3 Authority Key Identifier:
- keyid:4D:45:C1:68:38:BB:73:A9:69:A1:20:E7:ED:F5:22:A1:23:14:D7:9E
-
- X509v3 Key Usage: critical
- Digital Signature, Certificate Sign, CRL Sign
- Signature Algorithm: sha1WithRSAEncryption
- 67:6b:06:b9:5f:45:3b:2a:4b:33:b3:e6:1b:6b:59:4e:22:cc:
- b9:b7:a4:25:c9:a7:c4:f0:54:96:0b:64:f3:b1:58:4f:5e:51:
- fc:b2:97:7b:27:65:c2:e5:ca:e7:0d:0c:25:7b:62:e3:fa:9f:
- b4:87:b7:45:46:af:83:a5:97:48:8c:a5:bd:f1:16:2b:9b:76:
- 2c:7a:35:60:6c:11:80:97:cc:a9:92:52:e6:2b:e6:69:ed:a9:
- f8:36:2d:2c:77:bf:61:48:d1:63:0b:b9:5b:52:ed:18:b0:43:
- 42:22:a6:b1:77:ae:de:69:c5:cd:c7:1c:a1:b1:a5:1c:10:fb:
- 18:be:1a:70:dd:c1:92:4b:be:29:5a:9d:3f:35:be:e5:7d:51:
- f8:55:e0:25:75:23:87:1e:5c:dc:ba:9d:b0:ac:b3:69:db:17:
- 83:c9:f7:de:0c:bc:08:dc:91:9e:a8:d0:d7:15:37:73:a5:35:
- b8:fc:7e:c5:44:40:06:c3:eb:f8:22:80:5c:47:ce:02:e3:11:
- 9f:44:ff:fd:9a:32:cc:7d:64:51:0e:eb:57:26:76:3a:e3:1e:
- 22:3c:c2:a6:36:dd:19:ef:a7:fc:12:f3:26:c0:59:31:85:4c:
- 9c:d8:cf:df:a4:cc:cc:29:93:ff:94:6d:76:5c:13:08:97:f2:
- ed:a5:0b:4d:dd:e8:c9:68:0e:66:d3:00:0e:33:12:5b:bc:95:
- e5:32:90:a8:b3:c6:6c:83:ad:77:ee:8b:7e:7e:b1:a9:ab:d3:
- e1:f1:b6:c0:b1:ea:88:c0:e7:d3:90:e9:28:92:94:7b:68:7b:
- 97:2a:0a:67:2d:85:02:38:10:e4:03:61:d4:da:25:36:c7:08:
- 58:2d:a1:a7:51:af:30:0a:49:f5:a6:69:87:07:2d:44:46:76:
- 8e:2a:e5:9a:3b:d7:18:a2:fc:9c:38:10:cc:c6:3b:d2:b5:17:
- 3a:6f:fd:ae:25:bd:f5:72:59:64:b1:74:2a:38:5f:18:4c:df:
- cf:71:04:5a:36:d4:bf:2f:99:9c:e8:d9:ba:b1:95:e6:02:4b:
- 21:a1:5b:d5:c1:4f:8f:ae:69:6d:53:db:01:93:b5:5c:1e:18:
- dd:64:5a:ca:18:28:3e:63:04:11:fd:1c:8d:00:0f:b8:37:df:
- 67:8a:9d:66:a9:02:6a:91:ff:13:ca:2f:5d:83:bc:87:93:6c:
- dc:24:51:16:04:25:66:fa:b3:d9:c2:ba:29:be:9a:48:38:82:
- 99:f4:bf:3b:4a:31:19:f9:bf:8e:21:33:14:ca:4f:54:5f:fb:
- ce:fb:8f:71:7f:fd:5e:19:a0:0f:4b:91:b8:c4:54:bc:06:b0:
- 45:8f:26:91:a2:8e:fe:a9
-SHA1 Fingerprint=85:B5:FF:67:9B:0C:79:96:1F:C8:6E:44:22:00:46:13:DB:17:92:84
diff --git a/luni/src/main/files/cacerts/3c6676aa.0 b/luni/src/main/files/cacerts/3c6676aa.0
new file mode 100644
index 0000000..2905a24
--- /dev/null
+++ b/luni/src/main/files/cacerts/3c6676aa.0
@@ -0,0 +1,120 @@
+-----BEGIN CERTIFICATE-----
+MIIFcDCCA1igAwIBAgIEAJiWjTANBgkqhkiG9w0BAQsFADBYMQswCQYDVQQGEwJO
+TDEeMBwGA1UECgwVU3RhYXQgZGVyIE5lZGVybGFuZGVuMSkwJwYDVQQDDCBTdGFh
+dCBkZXIgTmVkZXJsYW5kZW4gRVYgUm9vdCBDQTAeFw0xMDEyMDgxMTE5MjlaFw0y
+MjEyMDgxMTEwMjhaMFgxCzAJBgNVBAYTAk5MMR4wHAYDVQQKDBVTdGFhdCBkZXIg
+TmVkZXJsYW5kZW4xKTAnBgNVBAMMIFN0YWF0IGRlciBOZWRlcmxhbmRlbiBFViBS
+b290IENBMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA48d+ifkkSzrS
+M4M1LGns3Amk41GoJSt5uAg94JG6hIXGhaTK5skuU6TJJB79VWZxXSzFYGgEt9nC
+UiY4iKTWO0Cmws0/zZiTs1QUWJZV1VD+hq2kY39ch/aO5ieSZxeSAgMs3NZmdO3d
+Z//BYY1jTw+bbRcwJu+r0h8QoPnFfxZpgQNH7R5ojXKhTbImxrpsX23Wr9GxE46p
+rfNeaXUmGD5BKyF/7otdBwadQ8QpCiv8Kj6GyzyDOvnJDdrFmeK8eEEzduG/L13l
+pJhQDBXd4Pqcfzho0LKmeqfRMb1+ilgnQ7O6M5HTp5gVXJrm0w912fxBmJc+qiXb
+j5IusHsMX/FjqTf5m3VpTCgmJdrV8hJwRVXj33NeN/UhbJCONVrJ0yPr08C+eKxC
+KFhmpUZtcALXEPlLVPxdhkqHz3/KRawRWrUgUY0viEeXOcDPusBCAUCZSCELa6fS
+/ZbV0b5GnUngC6agIk440ME8MLxwjyx1zNDFjFE7PZQIZCZhfbnDZY8UnCHQqv0X
+cgOPvZuM5l5Tnrmd74K74bzickFbIZTTRTeU0d8JOV3nI6qaHcptqAqGhYqCvkIH
+1vI4gnPah1vlPNOePqc7nvQDs/nxfRN0Av+7oeX6AHkcpmZBiFxgV6YuCcS6/ZrP
+px9Aw7vMWgpVSzs4dlG4Y4uElBbmVvMCAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB
+/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFP6rAJCYniT8qcwaivsnuL8wbqg7
+MA0GCSqGSIb3DQEBCwUAA4ICAQDPdyxuVr5Os7aEAJSrR8kN0nbHhp8dB9O2tLsI
+eK9p0gtJ3jPFrK3CiAJ9Brc1AsFgyb/E6JTe1NOpEyVa/m6irn0F3H3zbPB+po3u
+2dfOWBfoqSmuc0iH55vKbimhZF8ZE/euBhD/UcabTVUlT5OZEAFTdfETzsemQUHS
+v4ilf0X8rLiltTMMgsT7B/Zq5SWEXwbKwYY5EdtYzXc7LMJMD16a4/CrPmEbUCTC
+wPTxGfARKbalGAKb12NMcIxHowNDXLldRqANb/9Zjr7dn3LDWyvfjFvO5QxGbJKy
+CqNMVEIYFRIYvdr8unRu/8G2oGTYqV9Vrp9canaW2HNnh/tNf1zuacpzEPuKqf2e
+vTY4SUmH9A4U8OmHuD+nT3pajnnUk+S7aFKErGzp85hwVXIy+TSrK0m1zSBi5Dp6
+Z2Orltxtrpfs/J92VoguZs9btsmksNcFuuEnL5O7Jiqik7Ab846+HUCjuTaPPoIa
+Gl6I6lD4WeKDRikL40Rc4ZW2aZCaFG+XroHPaO+Zmr615+F/+PoTRxZMzG0IQOeL
+eG9QgkRQP2YGiqtDhFZKDyAthg710tvSeopLzaXoTvFeJiUBWSOgftL2fiFX1ye8
+FVdMpEbB4IMeDExNH08GGeL5qPQ6gqGyeUN51q1veieQA6TqJIc/2b3Z6fJfUEkc
+7uzXLg==
+-----END CERTIFICATE-----
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number: 10000013 (0x98968d)
+ Signature Algorithm: sha256WithRSAEncryption
+ Issuer: C=NL, O=Staat der Nederlanden, CN=Staat der Nederlanden EV Root CA
+ Validity
+ Not Before: Dec 8 11:19:29 2010 GMT
+ Not After : Dec 8 11:10:28 2022 GMT
+ Subject: C=NL, O=Staat der Nederlanden, CN=Staat der Nederlanden EV Root CA
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ Public-Key: (4096 bit)
+ Modulus:
+ 00:e3:c7:7e:89:f9:24:4b:3a:d2:33:83:35:2c:69:
+ ec:dc:09:a4:e3:51:a8:25:2b:79:b8:08:3d:e0:91:
+ ba:84:85:c6:85:a4:ca:e6:c9:2e:53:a4:c9:24:1e:
+ fd:55:66:71:5d:2c:c5:60:68:04:b7:d9:c2:52:26:
+ 38:88:a4:d6:3b:40:a6:c2:cd:3f:cd:98:93:b3:54:
+ 14:58:96:55:d5:50:fe:86:ad:a4:63:7f:5c:87:f6:
+ 8e:e6:27:92:67:17:92:02:03:2c:dc:d6:66:74:ed:
+ dd:67:ff:c1:61:8d:63:4f:0f:9b:6d:17:30:26:ef:
+ ab:d2:1f:10:a0:f9:c5:7f:16:69:81:03:47:ed:1e:
+ 68:8d:72:a1:4d:b2:26:c6:ba:6c:5f:6d:d6:af:d1:
+ b1:13:8e:a9:ad:f3:5e:69:75:26:18:3e:41:2b:21:
+ 7f:ee:8b:5d:07:06:9d:43:c4:29:0a:2b:fc:2a:3e:
+ 86:cb:3c:83:3a:f9:c9:0d:da:c5:99:e2:bc:78:41:
+ 33:76:e1:bf:2f:5d:e5:a4:98:50:0c:15:dd:e0:fa:
+ 9c:7f:38:68:d0:b2:a6:7a:a7:d1:31:bd:7e:8a:58:
+ 27:43:b3:ba:33:91:d3:a7:98:15:5c:9a:e6:d3:0f:
+ 75:d9:fc:41:98:97:3e:aa:25:db:8f:92:2e:b0:7b:
+ 0c:5f:f1:63:a9:37:f9:9b:75:69:4c:28:26:25:da:
+ d5:f2:12:70:45:55:e3:df:73:5e:37:f5:21:6c:90:
+ 8e:35:5a:c9:d3:23:eb:d3:c0:be:78:ac:42:28:58:
+ 66:a5:46:6d:70:02:d7:10:f9:4b:54:fc:5d:86:4a:
+ 87:cf:7f:ca:45:ac:11:5a:b5:20:51:8d:2f:88:47:
+ 97:39:c0:cf:ba:c0:42:01:40:99:48:21:0b:6b:a7:
+ d2:fd:96:d5:d1:be:46:9d:49:e0:0b:a6:a0:22:4e:
+ 38:d0:c1:3c:30:bc:70:8f:2c:75:cc:d0:c5:8c:51:
+ 3b:3d:94:08:64:26:61:7d:b9:c3:65:8f:14:9c:21:
+ d0:aa:fd:17:72:03:8f:bd:9b:8c:e6:5e:53:9e:b9:
+ 9d:ef:82:bb:e1:bc:e2:72:41:5b:21:94:d3:45:37:
+ 94:d1:df:09:39:5d:e7:23:aa:9a:1d:ca:6d:a8:0a:
+ 86:85:8a:82:be:42:07:d6:f2:38:82:73:da:87:5b:
+ e5:3c:d3:9e:3e:a7:3b:9e:f4:03:b3:f9:f1:7d:13:
+ 74:02:ff:bb:a1:e5:fa:00:79:1c:a6:66:41:88:5c:
+ 60:57:a6:2e:09:c4:ba:fd:9a:cf:a7:1f:40:c3:bb:
+ cc:5a:0a:55:4b:3b:38:76:51:b8:63:8b:84:94:16:
+ e6:56:f3
+ Exponent: 65537 (0x10001)
+ X509v3 extensions:
+ X509v3 Basic Constraints: critical
+ CA:TRUE
+ X509v3 Key Usage: critical
+ Certificate Sign, CRL Sign
+ X509v3 Subject Key Identifier:
+ FE:AB:00:90:98:9E:24:FC:A9:CC:1A:8A:FB:27:B8:BF:30:6E:A8:3B
+ Signature Algorithm: sha256WithRSAEncryption
+ cf:77:2c:6e:56:be:4e:b3:b6:84:00:94:ab:47:c9:0d:d2:76:
+ c7:86:9f:1d:07:d3:b6:b4:bb:08:78:af:69:d2:0b:49:de:33:
+ c5:ac:ad:c2:88:02:7d:06:b7:35:02:c1:60:c9:bf:c4:e8:94:
+ de:d4:d3:a9:13:25:5a:fe:6e:a2:ae:7d:05:dc:7d:f3:6c:f0:
+ 7e:a6:8d:ee:d9:d7:ce:58:17:e8:a9:29:ae:73:48:87:e7:9b:
+ ca:6e:29:a1:64:5f:19:13:f7:ae:06:10:ff:51:c6:9b:4d:55:
+ 25:4f:93:99:10:01:53:75:f1:13:ce:c7:a6:41:41:d2:bf:88:
+ a5:7f:45:fc:ac:b8:a5:b5:33:0c:82:c4:fb:07:f6:6a:e5:25:
+ 84:5f:06:ca:c1:86:39:11:db:58:cd:77:3b:2c:c2:4c:0f:5e:
+ 9a:e3:f0:ab:3e:61:1b:50:24:c2:c0:f4:f1:19:f0:11:29:b6:
+ a5:18:02:9b:d7:63:4c:70:8c:47:a3:03:43:5c:b9:5d:46:a0:
+ 0d:6f:ff:59:8e:be:dd:9f:72:c3:5b:2b:df:8c:5b:ce:e5:0c:
+ 46:6c:92:b2:0a:a3:4c:54:42:18:15:12:18:bd:da:fc:ba:74:
+ 6e:ff:c1:b6:a0:64:d8:a9:5f:55:ae:9f:5c:6a:76:96:d8:73:
+ 67:87:fb:4d:7f:5c:ee:69:ca:73:10:fb:8a:a9:fd:9e:bd:36:
+ 38:49:49:87:f4:0e:14:f0:e9:87:b8:3f:a7:4f:7a:5a:8e:79:
+ d4:93:e4:bb:68:52:84:ac:6c:e9:f3:98:70:55:72:32:f9:34:
+ ab:2b:49:b5:cd:20:62:e4:3a:7a:67:63:ab:96:dc:6d:ae:97:
+ ec:fc:9f:76:56:88:2e:66:cf:5b:b6:c9:a4:b0:d7:05:ba:e1:
+ 27:2f:93:bb:26:2a:a2:93:b0:1b:f3:8e:be:1d:40:a3:b9:36:
+ 8f:3e:82:1a:1a:5e:88:ea:50:f8:59:e2:83:46:29:0b:e3:44:
+ 5c:e1:95:b6:69:90:9a:14:6f:97:ae:81:cf:68:ef:99:9a:be:
+ b5:e7:e1:7f:f8:fa:13:47:16:4c:cc:6d:08:40:e7:8b:78:6f:
+ 50:82:44:50:3f:66:06:8a:ab:43:84:56:4a:0f:20:2d:86:0e:
+ f5:d2:db:d2:7a:8a:4b:cd:a5:e8:4e:f1:5e:26:25:01:59:23:
+ a0:7e:d2:f6:7e:21:57:d7:27:bc:15:57:4c:a4:46:c1:e0:83:
+ 1e:0c:4c:4d:1f:4f:06:19:e2:f9:a8:f4:3a:82:a1:b2:79:43:
+ 79:d6:ad:6f:7a:27:90:03:a4:ea:24:87:3f:d9:bd:d9:e9:f2:
+ 5f:50:49:1c:ee:ec:d7:2e
+SHA1 Fingerprint=76:E2:7E:C1:4F:DB:82:C1:C0:A6:75:B5:05:BE:3D:29:B4:ED:DB:BB
diff --git a/luni/src/main/files/cacerts/4be590e0.0 b/luni/src/main/files/cacerts/4be590e0.0
new file mode 100644
index 0000000..788aff7
--- /dev/null
+++ b/luni/src/main/files/cacerts/4be590e0.0
@@ -0,0 +1,120 @@
+-----BEGIN CERTIFICATE-----
+MIIFZjCCA06gAwIBAgIQCgFCgAAAAUUjz0Z8AAAAAjANBgkqhkiG9w0BAQsFADBN
+MQswCQYDVQQGEwJVUzESMBAGA1UEChMJSWRlblRydXN0MSowKAYDVQQDEyFJZGVu
+VHJ1c3QgUHVibGljIFNlY3RvciBSb290IENBIDEwHhcNMTQwMTE2MTc1MzMyWhcN
+MzQwMTE2MTc1MzMyWjBNMQswCQYDVQQGEwJVUzESMBAGA1UEChMJSWRlblRydXN0
+MSowKAYDVQQDEyFJZGVuVHJ1c3QgUHVibGljIFNlY3RvciBSb290IENBIDEwggIi
+MA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC2IpT8pEiv6EdrCvsnduTyP4o7
+ekosMSqMjbCpwzFrqHd2hCa2rIFCDQjrVVi7evi8ZX3yoG2LqEfpYnYeEe4IFNGy
+RBb06tD6Hi9e28tzQa68ALBKK0CyrOE7S8ItneShm+waOh7wCLPQ5CQ1B5+ctMlS
+bdsHyo+1W/CD80/HLaXIrcuVIKQxKFdYWuSNG5qrng0M8gozOSI5Cpcu81N3uURF
+/YTLNiCBWS2ab21ISGHKTN9T0a9SvESfqy9rg3LvdYDaBjMbXcjaY8ZNzaxmMc3R
+3j6HEDbhuaR672BQssvKplbgN6+rNBM5Jeg5ZuSYeqoSmJxZZoY+rfGwyj4GD3vw
+EUs3oERte8uojHH01bWRNszwFcYr3lEXsZdMUD2xlVl8BX0tIdUAvwFnol57plzy
+9yLxkA2T26pEUWbMfXYD62qoKjgZl3YNa4ph+bz27nb9cCvdKTz4Ch5bQhyLVi9V
+GxyhLrXHFub4qjySjmm2AcG1hp2JDws4lFTo6tyePSW8Uybt1as5qsVATFSrsrTZ
+2fjXctscvG29ZV/viDUqZi/u9rNl8DONfJhBaUYPQxxp+pu10GFqzcpL2UyQRqsV
+WaFHVCkugyhfHMKiq3IXAAaOReyL4jM9f9oZRORicsPfIsbyVtTdX5Vy7W1f90gD
+W/3FKqD2cyOEEBsB5wIDAQABo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/
+BAUwAwEB/zAdBgNVHQ4EFgQU43HgntinQtnbcZFrlJPrw6PRFKMwDQYJKoZIhvcN
+AQELBQADggIBAEf63QqwEZE4rU1d9+UOl1QZgkiHVIyqZJnYWv6IAcVYpZmxI1Qj
+t2odIFflAWJBF9MJ23XLblSQdf4an4EKwt3X9wnQW3IV5B4Jaj0z8yGa5hV+rVHV
+DRDtfULAj+7AmgjVQdZcDiFpboBhDhXAuM/FSRJSzL46zNQuOAXeNf0fb7iAaJg9
+TaDKQGXSc3z1i9kKlT/YPyNtGtEqJBnZhbMX73huqVjRI9PHE+1yJX9dsXNw0H8G
+lwmEKYBhHfpe/3OsoOOJuBxxFcbeMX8S3OFtm6/n6J91eEyrRjuazr8FGF1NFTwW
+mhlQBJqymm9li1JfPFgEKCXAZmExfrngdbkaqIHWchezxQMxNRF4eKLg6TCMf4Df
+WN88uieW4oA0beOY02QnrEh+KHdcxiVhJfiFDGX6xDIvpZgF5PgLZxYWxoK4Mhn5
++bl53B/N66+rDt0b20XkeucC4pVd/GnwU2lhlXV5C15V5jgclKlZM57IcXR5f1GJ
+tshquDDIajjDbp7hNxbqBWJMWxJH7ae0s1hWx0nzfxJoCTFx8G34Tkf71oXuxVhA
+GaQdp/lLQzfcaFpPz+vCZHTetBXZ9FRUGi8c15dxVJCO2SCdUyt/q4/i6jC8UDfv
+8Ue1fXwsBOxonbRJRBD0ckscZOf85muQ3Wl9af0AVqW3rLatt8o+Ae+c
+-----END CERTIFICATE-----
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number:
+ 0a:01:42:80:00:00:01:45:23:cf:46:7c:00:00:00:02
+ Signature Algorithm: sha256WithRSAEncryption
+ Issuer: C=US, O=IdenTrust, CN=IdenTrust Public Sector Root CA 1
+ Validity
+ Not Before: Jan 16 17:53:32 2014 GMT
+ Not After : Jan 16 17:53:32 2034 GMT
+ Subject: C=US, O=IdenTrust, CN=IdenTrust Public Sector Root CA 1
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ Public-Key: (4096 bit)
+ Modulus:
+ 00:b6:22:94:fc:a4:48:af:e8:47:6b:0a:fb:27:76:
+ e4:f2:3f:8a:3b:7a:4a:2c:31:2a:8c:8d:b0:a9:c3:
+ 31:6b:a8:77:76:84:26:b6:ac:81:42:0d:08:eb:55:
+ 58:bb:7a:f8:bc:65:7d:f2:a0:6d:8b:a8:47:e9:62:
+ 76:1e:11:ee:08:14:d1:b2:44:16:f4:ea:d0:fa:1e:
+ 2f:5e:db:cb:73:41:ae:bc:00:b0:4a:2b:40:b2:ac:
+ e1:3b:4b:c2:2d:9d:e4:a1:9b:ec:1a:3a:1e:f0:08:
+ b3:d0:e4:24:35:07:9f:9c:b4:c9:52:6d:db:07:ca:
+ 8f:b5:5b:f0:83:f3:4f:c7:2d:a5:c8:ad:cb:95:20:
+ a4:31:28:57:58:5a:e4:8d:1b:9a:ab:9e:0d:0c:f2:
+ 0a:33:39:22:39:0a:97:2e:f3:53:77:b9:44:45:fd:
+ 84:cb:36:20:81:59:2d:9a:6f:6d:48:48:61:ca:4c:
+ df:53:d1:af:52:bc:44:9f:ab:2f:6b:83:72:ef:75:
+ 80:da:06:33:1b:5d:c8:da:63:c6:4d:cd:ac:66:31:
+ cd:d1:de:3e:87:10:36:e1:b9:a4:7a:ef:60:50:b2:
+ cb:ca:a6:56:e0:37:af:ab:34:13:39:25:e8:39:66:
+ e4:98:7a:aa:12:98:9c:59:66:86:3e:ad:f1:b0:ca:
+ 3e:06:0f:7b:f0:11:4b:37:a0:44:6d:7b:cb:a8:8c:
+ 71:f4:d5:b5:91:36:cc:f0:15:c6:2b:de:51:17:b1:
+ 97:4c:50:3d:b1:95:59:7c:05:7d:2d:21:d5:00:bf:
+ 01:67:a2:5e:7b:a6:5c:f2:f7:22:f1:90:0d:93:db:
+ aa:44:51:66:cc:7d:76:03:eb:6a:a8:2a:38:19:97:
+ 76:0d:6b:8a:61:f9:bc:f6:ee:76:fd:70:2b:dd:29:
+ 3c:f8:0a:1e:5b:42:1c:8b:56:2f:55:1b:1c:a1:2e:
+ b5:c7:16:e6:f8:aa:3c:92:8e:69:b6:01:c1:b5:86:
+ 9d:89:0f:0b:38:94:54:e8:ea:dc:9e:3d:25:bc:53:
+ 26:ed:d5:ab:39:aa:c5:40:4c:54:ab:b2:b4:d9:d9:
+ f8:d7:72:db:1c:bc:6d:bd:65:5f:ef:88:35:2a:66:
+ 2f:ee:f6:b3:65:f0:33:8d:7c:98:41:69:46:0f:43:
+ 1c:69:fa:9b:b5:d0:61:6a:cd:ca:4b:d9:4c:90:46:
+ ab:15:59:a1:47:54:29:2e:83:28:5f:1c:c2:a2:ab:
+ 72:17:00:06:8e:45:ec:8b:e2:33:3d:7f:da:19:44:
+ e4:62:72:c3:df:22:c6:f2:56:d4:dd:5f:95:72:ed:
+ 6d:5f:f7:48:03:5b:fd:c5:2a:a0:f6:73:23:84:10:
+ 1b:01:e7
+ Exponent: 65537 (0x10001)
+ X509v3 extensions:
+ X509v3 Key Usage: critical
+ Certificate Sign, CRL Sign
+ X509v3 Basic Constraints: critical
+ CA:TRUE
+ X509v3 Subject Key Identifier:
+ E3:71:E0:9E:D8:A7:42:D9:DB:71:91:6B:94:93:EB:C3:A3:D1:14:A3
+ Signature Algorithm: sha256WithRSAEncryption
+ 47:fa:dd:0a:b0:11:91:38:ad:4d:5d:f7:e5:0e:97:54:19:82:
+ 48:87:54:8c:aa:64:99:d8:5a:fe:88:01:c5:58:a5:99:b1:23:
+ 54:23:b7:6a:1d:20:57:e5:01:62:41:17:d3:09:db:75:cb:6e:
+ 54:90:75:fe:1a:9f:81:0a:c2:dd:d7:f7:09:d0:5b:72:15:e4:
+ 1e:09:6a:3d:33:f3:21:9a:e6:15:7e:ad:51:d5:0d:10:ed:7d:
+ 42:c0:8f:ee:c0:9a:08:d5:41:d6:5c:0e:21:69:6e:80:61:0e:
+ 15:c0:b8:cf:c5:49:12:52:cc:be:3a:cc:d4:2e:38:05:de:35:
+ fd:1f:6f:b8:80:68:98:3d:4d:a0:ca:40:65:d2:73:7c:f5:8b:
+ d9:0a:95:3f:d8:3f:23:6d:1a:d1:2a:24:19:d9:85:b3:17:ef:
+ 78:6e:a9:58:d1:23:d3:c7:13:ed:72:25:7f:5d:b1:73:70:d0:
+ 7f:06:97:09:84:29:80:61:1d:fa:5e:ff:73:ac:a0:e3:89:b8:
+ 1c:71:15:c6:de:31:7f:12:dc:e1:6d:9b:af:e7:e8:9f:75:78:
+ 4c:ab:46:3b:9a:ce:bf:05:18:5d:4d:15:3c:16:9a:19:50:04:
+ 9a:b2:9a:6f:65:8b:52:5f:3c:58:04:28:25:c0:66:61:31:7e:
+ b9:e0:75:b9:1a:a8:81:d6:72:17:b3:c5:03:31:35:11:78:78:
+ a2:e0:e9:30:8c:7f:80:df:58:df:3c:ba:27:96:e2:80:34:6d:
+ e3:98:d3:64:27:ac:48:7e:28:77:5c:c6:25:61:25:f8:85:0c:
+ 65:fa:c4:32:2f:a5:98:05:e4:f8:0b:67:16:16:c6:82:b8:32:
+ 19:f9:f9:b9:79:dc:1f:cd:eb:af:ab:0e:dd:1b:db:45:e4:7a:
+ e7:02:e2:95:5d:fc:69:f0:53:69:61:95:75:79:0b:5e:55:e6:
+ 38:1c:94:a9:59:33:9e:c8:71:74:79:7f:51:89:b6:c8:6a:b8:
+ 30:c8:6a:38:c3:6e:9e:e1:37:16:ea:05:62:4c:5b:12:47:ed:
+ a7:b4:b3:58:56:c7:49:f3:7f:12:68:09:31:71:f0:6d:f8:4e:
+ 47:fb:d6:85:ee:c5:58:40:19:a4:1d:a7:f9:4b:43:37:dc:68:
+ 5a:4f:cf:eb:c2:64:74:de:b4:15:d9:f4:54:54:1a:2f:1c:d7:
+ 97:71:54:90:8e:d9:20:9d:53:2b:7f:ab:8f:e2:ea:30:bc:50:
+ 37:ef:f1:47:b5:7d:7c:2c:04:ec:68:9d:b4:49:44:10:f4:72:
+ 4b:1c:64:e7:fc:e6:6b:90:dd:69:7d:69:fd:00:56:a5:b7:ac:
+ b6:ad:b7:ca:3e:01:ef:9c
+SHA1 Fingerprint=BA:29:41:60:77:98:3F:F4:F3:EF:F2:31:05:3B:2E:EA:6D:4D:45:FD
diff --git a/luni/src/main/files/cacerts/5021a0a2.0 b/luni/src/main/files/cacerts/5021a0a2.0
deleted file mode 100644
index 15f5213..0000000
--- a/luni/src/main/files/cacerts/5021a0a2.0
+++ /dev/null
@@ -1,84 +0,0 @@
------BEGIN CERTIFICATE-----
-MIID3TCCAsWgAwIBAgIOHaIAAQAC7LdggHiNtgYwDQYJKoZIhvcNAQEFBQAweTEL
-MAkGA1UEBhMCREUxHDAaBgNVBAoTE1RDIFRydXN0Q2VudGVyIEdtYkgxJDAiBgNV
-BAsTG1RDIFRydXN0Q2VudGVyIFVuaXZlcnNhbCBDQTEmMCQGA1UEAxMdVEMgVHJ1
-c3RDZW50ZXIgVW5pdmVyc2FsIENBIEkwHhcNMDYwMzIyMTU1NDI4WhcNMjUxMjMx
-MjI1OTU5WjB5MQswCQYDVQQGEwJERTEcMBoGA1UEChMTVEMgVHJ1c3RDZW50ZXIg
-R21iSDEkMCIGA1UECxMbVEMgVHJ1c3RDZW50ZXIgVW5pdmVyc2FsIENBMSYwJAYD
-VQQDEx1UQyBUcnVzdENlbnRlciBVbml2ZXJzYWwgQ0EgSTCCASIwDQYJKoZIhvcN
-AQEBBQADggEPADCCAQoCggEBAKR3I5ZEr5D0MacQ9CaHnPM42Q9e3s9B6DGtxnSR
-JJZ4Hgmgm5qVSkr1YnwCqMqs+1oEdjneX/H5s7/zA1hV0qq34wQi0fiU2iIIAI3T
-fCZdzHd55yx4Oagmcw6iXSVphU9VDprvxrlE4Vc93x9UIuVvZaozhDrzznq+VZeu
-jRIPFDPiUHDDSYcTvFHe15gSWu86gzOSBnWLknwSaHtwag+1m7Z3W0hZneTvWq3z
-wZ7U10VOylY0Ibw+F1tvdwxIAUMpsN0/lm7mlaoMwCC2/T42J5zjXM9OgdwZu5GQ
-fezmlwQek8wiSdeXhrYTCjxDI3d+8NzmzSQfO4ObNDqDNOMCAwEAAaNjMGEwHwYD
-VR0jBBgwFoAUkqR1LKSevoFE63n8isWVpesQdXMwDwYDVR0TAQH/BAUwAwEB/zAO
-BgNVHQ8BAf8EBAMCAYYwHQYDVR0OBBYEFJKkdSyknr6BROt5/IrFlaXrEHVzMA0G
-CSqGSIb3DQEBBQUAA4IBAQAo0uCG1eb4e/CX3CJrO5UUVg8RMKWaTzqwOuAGy2X1
-7caXJ/4l8lfmXpWMPmRgFVp/Lw0BxbFg/UU1z/CyvwbZ71q+s2IhtNerNXxTPqYn
-8aEt2hojnczd7Dwtnic0XQ/CNnm8yUpiLe1r2X1BQ3y2qsrtYbE3ghUJGooWMNjs
-ydZHcnhLEEYUjl8Or+zHL6sQ17bxbuyGssLoDZJz3KL0Dzq/YSMQiZxIQG5wALPT
-ujdEWBF6AmqI8Dc08BnprNRlc/ZpjGSUOnmFKbAWKwyCPwacx/0QK54PLLae4xW/
-2TYcuiUaUj0a7CIMHOCkoj3w6DnPgcB77V0fb8XQC9eY
------END CERTIFICATE-----
-Certificate:
- Data:
- Version: 3 (0x2)
- Serial Number:
- 1d:a2:00:01:00:02:ec:b7:60:80:78:8d:b6:06
- Signature Algorithm: sha1WithRSAEncryption
- Issuer: C=DE, O=TC TrustCenter GmbH, OU=TC TrustCenter Universal CA, CN=TC TrustCenter Universal CA I
- Validity
- Not Before: Mar 22 15:54:28 2006 GMT
- Not After : Dec 31 22:59:59 2025 GMT
- Subject: C=DE, O=TC TrustCenter GmbH, OU=TC TrustCenter Universal CA, CN=TC TrustCenter Universal CA I
- Subject Public Key Info:
- Public Key Algorithm: rsaEncryption
- Public-Key: (2048 bit)
- Modulus:
- 00:a4:77:23:96:44:af:90:f4:31:a7:10:f4:26:87:
- 9c:f3:38:d9:0f:5e:de:cf:41:e8:31:ad:c6:74:91:
- 24:96:78:1e:09:a0:9b:9a:95:4a:4a:f5:62:7c:02:
- a8:ca:ac:fb:5a:04:76:39:de:5f:f1:f9:b3:bf:f3:
- 03:58:55:d2:aa:b7:e3:04:22:d1:f8:94:da:22:08:
- 00:8d:d3:7c:26:5d:cc:77:79:e7:2c:78:39:a8:26:
- 73:0e:a2:5d:25:69:85:4f:55:0e:9a:ef:c6:b9:44:
- e1:57:3d:df:1f:54:22:e5:6f:65:aa:33:84:3a:f3:
- ce:7a:be:55:97:ae:8d:12:0f:14:33:e2:50:70:c3:
- 49:87:13:bc:51:de:d7:98:12:5a:ef:3a:83:33:92:
- 06:75:8b:92:7c:12:68:7b:70:6a:0f:b5:9b:b6:77:
- 5b:48:59:9d:e4:ef:5a:ad:f3:c1:9e:d4:d7:45:4e:
- ca:56:34:21:bc:3e:17:5b:6f:77:0c:48:01:43:29:
- b0:dd:3f:96:6e:e6:95:aa:0c:c0:20:b6:fd:3e:36:
- 27:9c:e3:5c:cf:4e:81:dc:19:bb:91:90:7d:ec:e6:
- 97:04:1e:93:cc:22:49:d7:97:86:b6:13:0a:3c:43:
- 23:77:7e:f0:dc:e6:cd:24:1f:3b:83:9b:34:3a:83:
- 34:e3
- Exponent: 65537 (0x10001)
- X509v3 extensions:
- X509v3 Authority Key Identifier:
- keyid:92:A4:75:2C:A4:9E:BE:81:44:EB:79:FC:8A:C5:95:A5:EB:10:75:73
-
- X509v3 Basic Constraints: critical
- CA:TRUE
- X509v3 Key Usage: critical
- Digital Signature, Certificate Sign, CRL Sign
- X509v3 Subject Key Identifier:
- 92:A4:75:2C:A4:9E:BE:81:44:EB:79:FC:8A:C5:95:A5:EB:10:75:73
- Signature Algorithm: sha1WithRSAEncryption
- 28:d2:e0:86:d5:e6:f8:7b:f0:97:dc:22:6b:3b:95:14:56:0f:
- 11:30:a5:9a:4f:3a:b0:3a:e0:06:cb:65:f5:ed:c6:97:27:fe:
- 25:f2:57:e6:5e:95:8c:3e:64:60:15:5a:7f:2f:0d:01:c5:b1:
- 60:fd:45:35:cf:f0:b2:bf:06:d9:ef:5a:be:b3:62:21:b4:d7:
- ab:35:7c:53:3e:a6:27:f1:a1:2d:da:1a:23:9d:cc:dd:ec:3c:
- 2d:9e:27:34:5d:0f:c2:36:79:bc:c9:4a:62:2d:ed:6b:d9:7d:
- 41:43:7c:b6:aa:ca:ed:61:b1:37:82:15:09:1a:8a:16:30:d8:
- ec:c9:d6:47:72:78:4b:10:46:14:8e:5f:0e:af:ec:c7:2f:ab:
- 10:d7:b6:f1:6e:ec:86:b2:c2:e8:0d:92:73:dc:a2:f4:0f:3a:
- bf:61:23:10:89:9c:48:40:6e:70:00:b3:d3:ba:37:44:58:11:
- 7a:02:6a:88:f0:37:34:f0:19:e9:ac:d4:65:73:f6:69:8c:64:
- 94:3a:79:85:29:b0:16:2b:0c:82:3f:06:9c:c7:fd:10:2b:9e:
- 0f:2c:b6:9e:e3:15:bf:d9:36:1c:ba:25:1a:52:3d:1a:ec:22:
- 0c:1c:e0:a4:a2:3d:f0:e8:39:cf:81:c0:7b:ed:5d:1f:6f:c5:
- d0:0b:d7:98
-SHA1 Fingerprint=6B:2F:34:AD:89:58:BE:62:FD:B0:6B:5C:CE:BB:9D:D9:4F:4E:39:F3
diff --git a/luni/src/main/files/cacerts/5a250ea7.0 b/luni/src/main/files/cacerts/5a250ea7.0
new file mode 100644
index 0000000..4561d51
--- /dev/null
+++ b/luni/src/main/files/cacerts/5a250ea7.0
@@ -0,0 +1,120 @@
+-----BEGIN CERTIFICATE-----
+MIIFdDCCA1ygAwIBAgIEAJiiOTANBgkqhkiG9w0BAQsFADBaMQswCQYDVQQGEwJO
+TDEeMBwGA1UECgwVU3RhYXQgZGVyIE5lZGVybGFuZGVuMSswKQYDVQQDDCJTdGFh
+dCBkZXIgTmVkZXJsYW5kZW4gUm9vdCBDQSAtIEczMB4XDTEzMTExNDExMjg0MloX
+DTI4MTExMzIzMDAwMFowWjELMAkGA1UEBhMCTkwxHjAcBgNVBAoMFVN0YWF0IGRl
+ciBOZWRlcmxhbmRlbjErMCkGA1UEAwwiU3RhYXQgZGVyIE5lZGVybGFuZGVuIFJv
+b3QgQ0EgLSBHMzCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAL4yolQP
+cPssXFnrbMSkUeiFKrPMSjTysF/zDsccPVMeiAho2G89rcKezIJnByeHaHE6n3WW
+IkYFsO2tx1ueKt6c/DrGlaf1F2cY5y9JCAxcz+bMNO14+1Cx3Gsy8KL+tjzk7FqX
+xz8ecAgwoNzFs21v0IJyEavSgWhZghe3eJJg+szeP4TrjTgzkApyI/o1zCZxMdFy
+KJLZWyNtZrVtB0LrpjPOktvA9mxjeM3KTj215VKb8b475lRgsGYeCasH/lSJEULR
+9yS6YHgamPfJEf0WwTUaVHXvQ9Plrk7O53vDxk5hUUurmkVLoR9BvUhTFXFkC4az
+5S6+zqQbwSmEorXLCCN2QyIkHxcE1G6cxvx/K2Ya7Irl1s9N9WMJtxU51nus6+N8
+6U78dULI7ViVDAZCopz35HCz33JvWjdAidiFpNfxC95DGdRKWCyMijmev4SH8RY7
+Ngzp07TKbBlBUgmhHbBqv4LvcFEhMtwFdozL92TkA1CvjJFnq8Xy7ljY3r735zHP
+bMk7ccHViLVlvMDoFxcHErVc0qsgk7TmgoNwNsXNo42ti+yjwUOH5kPiNL6VizXt
+BznaqB16nzaeErAMZRKQFWDZJkBE41ZgpRDUajz9QdwOWke275dhdU/Z/seyHdTt
+XUmzqWrLZoQT1Vyg3N9udwbRcXXIV2+vD3dbAgMBAAGjQjBAMA8GA1UdEwEB/wQF
+MAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBRUrfrHkleuyjWcLhL75Lpd
+INyUVzANBgkqhkiG9w0BAQsFAAOCAgEAMJmdBTLIXg47mAE6iqTnB/d6+Oea31BD
+U5cqPco8R5gu4RV78ZLzYdqQJRZlwJ9UXQ4DO1t3ApyEtg2YXzTdO2PCwyiBwpwp
+LiniyMMB8jPqKqrMCQj3ZWfGzd/TtiunvczRDnBfuCPRy5FOCvTIeuXZYzbB1N/8
+Ipf3YF3qKS9Ysr1YvY2WTxB1v0h7PVGHoTx0IsL8B3+A3MSs/mrBcDCw6Y5p4ixp
+gZQJut3+TcCDjJRYwEYgr5wfAvg1VUkvRtTA8KCWAg8zxXHzniN9lLf9OtMJgwYh
+/WA9rjLA0u6NpvDntIJ8CsxwyXmA+P5M9zWEGYox+wrZ13+b8KKaa8MFSu1BYBQw
+0aoRQm7TIwIEC8Zl3d1Sd9qBa7Ko+gE4uZbqKmxnl4mUnrzhVNXkanjvSr0rmj1A
+fsbAddJu+2gw7OyLnflJNZoaLNmzlTnVHpL3prllL+U9bTpITAjc5CgSKL59NVzq
+4BZ+Extq1z7XnvwtdbLBFNUjA9tbbws+eC8N3jONFrdI54OagQ97wUNNVQQXOEpR
+1VmiiXTTn74eS9fGbbeIJG9gkaSChVtWQbzQRKtqE77RLFi3EjNYsjdj3BP1lB0/
+QFH1T/U67cjF68IeHRaVesd+QnGTbksVtzDfqu1XhUisHWrdOWnk4Xl4vs4Fv6EM
+94B7IWcnMFk=
+-----END CERTIFICATE-----
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number: 10003001 (0x98a239)
+ Signature Algorithm: sha256WithRSAEncryption
+ Issuer: C=NL, O=Staat der Nederlanden, CN=Staat der Nederlanden Root CA - G3
+ Validity
+ Not Before: Nov 14 11:28:42 2013 GMT
+ Not After : Nov 13 23:00:00 2028 GMT
+ Subject: C=NL, O=Staat der Nederlanden, CN=Staat der Nederlanden Root CA - G3
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ Public-Key: (4096 bit)
+ Modulus:
+ 00:be:32:a2:54:0f:70:fb:2c:5c:59:eb:6c:c4:a4:
+ 51:e8:85:2a:b3:cc:4a:34:f2:b0:5f:f3:0e:c7:1c:
+ 3d:53:1e:88:08:68:d8:6f:3d:ad:c2:9e:cc:82:67:
+ 07:27:87:68:71:3a:9f:75:96:22:46:05:b0:ed:ad:
+ c7:5b:9e:2a:de:9c:fc:3a:c6:95:a7:f5:17:67:18:
+ e7:2f:49:08:0c:5c:cf:e6:cc:34:ed:78:fb:50:b1:
+ dc:6b:32:f0:a2:fe:b6:3c:e4:ec:5a:97:c7:3f:1e:
+ 70:08:30:a0:dc:c5:b3:6d:6f:d0:82:72:11:ab:d2:
+ 81:68:59:82:17:b7:78:92:60:fa:cc:de:3f:84:eb:
+ 8d:38:33:90:0a:72:23:fa:35:cc:26:71:31:d1:72:
+ 28:92:d9:5b:23:6d:66:b5:6d:07:42:eb:a6:33:ce:
+ 92:db:c0:f6:6c:63:78:cd:ca:4e:3d:b5:e5:52:9b:
+ f1:be:3b:e6:54:60:b0:66:1e:09:ab:07:fe:54:89:
+ 11:42:d1:f7:24:ba:60:78:1a:98:f7:c9:11:fd:16:
+ c1:35:1a:54:75:ef:43:d3:e5:ae:4e:ce:e7:7b:c3:
+ c6:4e:61:51:4b:ab:9a:45:4b:a1:1f:41:bd:48:53:
+ 15:71:64:0b:86:b3:e5:2e:be:ce:a4:1b:c1:29:84:
+ a2:b5:cb:08:23:76:43:22:24:1f:17:04:d4:6e:9c:
+ c6:fc:7f:2b:66:1a:ec:8a:e5:d6:cf:4d:f5:63:09:
+ b7:15:39:d6:7b:ac:eb:e3:7c:e9:4e:fc:75:42:c8:
+ ed:58:95:0c:06:42:a2:9c:f7:e4:70:b3:df:72:6f:
+ 5a:37:40:89:d8:85:a4:d7:f1:0b:de:43:19:d4:4a:
+ 58:2c:8c:8a:39:9e:bf:84:87:f1:16:3b:36:0c:e9:
+ d3:b4:ca:6c:19:41:52:09:a1:1d:b0:6a:bf:82:ef:
+ 70:51:21:32:dc:05:76:8c:cb:f7:64:e4:03:50:af:
+ 8c:91:67:ab:c5:f2:ee:58:d8:de:be:f7:e7:31:cf:
+ 6c:c9:3b:71:c1:d5:88:b5:65:bc:c0:e8:17:17:07:
+ 12:b5:5c:d2:ab:20:93:b4:e6:82:83:70:36:c5:cd:
+ a3:8d:ad:8b:ec:a3:c1:43:87:e6:43:e2:34:be:95:
+ 8b:35:ed:07:39:da:a8:1d:7a:9f:36:9e:12:b0:0c:
+ 65:12:90:15:60:d9:26:40:44:e3:56:60:a5:10:d4:
+ 6a:3c:fd:41:dc:0e:5a:47:b6:ef:97:61:75:4f:d9:
+ fe:c7:b2:1d:d4:ed:5d:49:b3:a9:6a:cb:66:84:13:
+ d5:5c:a0:dc:df:6e:77:06:d1:71:75:c8:57:6f:af:
+ 0f:77:5b
+ Exponent: 65537 (0x10001)
+ X509v3 extensions:
+ X509v3 Basic Constraints: critical
+ CA:TRUE
+ X509v3 Key Usage: critical
+ Certificate Sign, CRL Sign
+ X509v3 Subject Key Identifier:
+ 54:AD:FA:C7:92:57:AE:CA:35:9C:2E:12:FB:E4:BA:5D:20:DC:94:57
+ Signature Algorithm: sha256WithRSAEncryption
+ 30:99:9d:05:32:c8:5e:0e:3b:98:01:3a:8a:a4:e7:07:f7:7a:
+ f8:e7:9a:df:50:43:53:97:2a:3d:ca:3c:47:98:2e:e1:15:7b:
+ f1:92:f3:61:da:90:25:16:65:c0:9f:54:5d:0e:03:3b:5b:77:
+ 02:9c:84:b6:0d:98:5f:34:dd:3b:63:c2:c3:28:81:c2:9c:29:
+ 2e:29:e2:c8:c3:01:f2:33:ea:2a:aa:cc:09:08:f7:65:67:c6:
+ cd:df:d3:b6:2b:a7:bd:cc:d1:0e:70:5f:b8:23:d1:cb:91:4e:
+ 0a:f4:c8:7a:e5:d9:63:36:c1:d4:df:fc:22:97:f7:60:5d:ea:
+ 29:2f:58:b2:bd:58:bd:8d:96:4f:10:75:bf:48:7b:3d:51:87:
+ a1:3c:74:22:c2:fc:07:7f:80:dc:c4:ac:fe:6a:c1:70:30:b0:
+ e9:8e:69:e2:2c:69:81:94:09:ba:dd:fe:4d:c0:83:8c:94:58:
+ c0:46:20:af:9c:1f:02:f8:35:55:49:2f:46:d4:c0:f0:a0:96:
+ 02:0f:33:c5:71:f3:9e:23:7d:94:b7:fd:3a:d3:09:83:06:21:
+ fd:60:3d:ae:32:c0:d2:ee:8d:a6:f0:e7:b4:82:7c:0a:cc:70:
+ c9:79:80:f8:fe:4c:f7:35:84:19:8a:31:fb:0a:d9:d7:7f:9b:
+ f0:a2:9a:6b:c3:05:4a:ed:41:60:14:30:d1:aa:11:42:6e:d3:
+ 23:02:04:0b:c6:65:dd:dd:52:77:da:81:6b:b2:a8:fa:01:38:
+ b9:96:ea:2a:6c:67:97:89:94:9e:bc:e1:54:d5:e4:6a:78:ef:
+ 4a:bd:2b:9a:3d:40:7e:c6:c0:75:d2:6e:fb:68:30:ec:ec:8b:
+ 9d:f9:49:35:9a:1a:2c:d9:b3:95:39:d5:1e:92:f7:a6:b9:65:
+ 2f:e5:3d:6d:3a:48:4c:08:dc:e4:28:12:28:be:7d:35:5c:ea:
+ e0:16:7e:13:1b:6a:d7:3e:d7:9e:fc:2d:75:b2:c1:14:d5:23:
+ 03:db:5b:6f:0b:3e:78:2f:0d:de:33:8d:16:b7:48:e7:83:9a:
+ 81:0f:7b:c1:43:4d:55:04:17:38:4a:51:d5:59:a2:89:74:d3:
+ 9f:be:1e:4b:d7:c6:6d:b7:88:24:6f:60:91:a4:82:85:5b:56:
+ 41:bc:d0:44:ab:6a:13:be:d1:2c:58:b7:12:33:58:b2:37:63:
+ dc:13:f5:94:1d:3f:40:51:f5:4f:f5:3a:ed:c8:c5:eb:c2:1e:
+ 1d:16:95:7a:c7:7e:42:71:93:6e:4b:15:b7:30:df:aa:ed:57:
+ 85:48:ac:1d:6a:dd:39:69:e4:e1:79:78:be:ce:05:bf:a1:0c:
+ f7:80:7b:21:67:27:30:59
+SHA1 Fingerprint=D8:EB:6B:41:51:92:59:E0:F3:E7:85:00:C0:3D:B6:88:97:C9:EE:FC
diff --git a/luni/src/main/files/cacerts/6645de82.0 b/luni/src/main/files/cacerts/6645de82.0
new file mode 100644
index 0000000..4b1ee7b
--- /dev/null
+++ b/luni/src/main/files/cacerts/6645de82.0
@@ -0,0 +1,82 @@
+-----BEGIN CERTIFICATE-----
+MIIEJjCCAw6gAwIBAgIGfaHyZeyKMA0GCSqGSIb3DQEBCwUAMIGxMQswCQYDVQQG
+EwJUUjEPMA0GA1UEBwwGQW5rYXJhMU0wSwYDVQQKDERUw5xSS1RSVVNUIEJpbGdp
+IMSwbGV0acWfaW0gdmUgQmlsacWfaW0gR8O8dmVubGnEn2kgSGl6bWV0bGVyaSBB
+LsWeLjFCMEAGA1UEAww5VMOcUktUUlVTVCBFbGVrdHJvbmlrIFNlcnRpZmlrYSBI
+aXptZXQgU2HEn2xhecSxY8Sxc8SxIEg2MB4XDTEzMTIxODA5MDQxMFoXDTIzMTIx
+NjA5MDQxMFowgbExCzAJBgNVBAYTAlRSMQ8wDQYDVQQHDAZBbmthcmExTTBLBgNV
+BAoMRFTDnFJLVFJVU1QgQmlsZ2kgxLBsZXRpxZ9pbSB2ZSBCaWxpxZ9pbSBHw7x2
+ZW5sacSfaSBIaXptZXRsZXJpIEEuxZ4uMUIwQAYDVQQDDDlUw5xSS1RSVVNUIEVs
+ZWt0cm9uaWsgU2VydGlmaWthIEhpem1ldCBTYcSfbGF5xLFjxLFzxLEgSDYwggEi
+MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCdsGjW6L0UlqMACprx9MfMkU1x
+eHe59yEmFXNRFpQJRwXiM/VomjX/3EsvMsew7eKC5W/a2uqsxgbPJQ1BgfbBOCK9
++bGlprMBvD9QFyv26WZV1DOzXPhDIHiTVRZwGTLmiddk671IUP320EEDwnS3/faA
+z1vFq6TWlRKb55cTMgPp1KtDWxbtMyJkKbbSk60vbNg9tvYdDjTu0n2pVQ8g9P0p
+u5FbHH3GQjhtQiht1AH7zYiXSX6484P4tZgvsycLSF5W506jM7NE1qXyGJTtHB6p
+lVxiSvgNZ1GpryHV+DKdeboaX+UEVU0TRv/yz3THGmNtwx8XEsMeED5gCLMxAgMB
+AAGjQjBAMB0GA1UdDgQWBBTdVRcT9qzoSCHK77Wv0QAy7Z6MtTAOBgNVHQ8BAf8E
+BAMCAQYwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAb1gNl0Oq
+FlQ+v6nfkkU/hQu7VtMMUszIv3ZnXuaqs6fvuay0EBQNdH49ba3RfdCaqaXKGDsC
+QC4qnFAUi/5XfldcEQlLNkVS9z2sFP1E34uXI9TDwe7UU5X+LEr+DXCqu4svLcsy
+o4LyVN/Y8t3XSHLuSqMplsNEzm61kod2pLv0kmzOLBQJZo6NrRa1xxsJYTvjIKID
+gI6tflEATseWhvtDmHd9KMeP2Cpu54Rvl0EpABZeTeIT6lnAY2c6RPuY/ATTMHKm
+9ocJV612ph1jmv3XZch4gyt1O6VbuA1df74jrlZVlFjvH4GMKrLN5ptjnhi85WsG
+tAuYSyher4hYyw==
+-----END CERTIFICATE-----
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number: 138134509972618 (0x7da1f265ec8a)
+ Signature Algorithm: sha256WithRSAEncryption
+ Issuer: C=TR, L=Ankara, O=T\xC3\x9CRKTRUST Bilgi \xC4\xB0leti\xC5\x9Fim ve Bili\xC5\x9Fim G\xC3\xBCvenli\xC4\x9Fi Hizmetleri A.\xC5\x9E., CN=T\xC3\x9CRKTRUST Elektronik Sertifika Hizmet Sa\xC4\x9Flay\xC4\xB1c\xC4\xB1s\xC4\xB1 H6
+ Validity
+ Not Before: Dec 18 09:04:10 2013 GMT
+ Not After : Dec 16 09:04:10 2023 GMT
+ Subject: C=TR, L=Ankara, O=T\xC3\x9CRKTRUST Bilgi \xC4\xB0leti\xC5\x9Fim ve Bili\xC5\x9Fim G\xC3\xBCvenli\xC4\x9Fi Hizmetleri A.\xC5\x9E., CN=T\xC3\x9CRKTRUST Elektronik Sertifika Hizmet Sa\xC4\x9Flay\xC4\xB1c\xC4\xB1s\xC4\xB1 H6
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ Public-Key: (2048 bit)
+ Modulus:
+ 00:9d:b0:68:d6:e8:bd:14:96:a3:00:0a:9a:f1:f4:
+ c7:cc:91:4d:71:78:77:b9:f7:21:26:15:73:51:16:
+ 94:09:47:05:e2:33:f5:68:9a:35:ff:dc:4b:2f:32:
+ c7:b0:ed:e2:82:e5:6f:da:da:ea:ac:c6:06:cf:25:
+ 0d:41:81:f6:c1:38:22:bd:f9:b1:a5:a6:b3:01:bc:
+ 3f:50:17:2b:f6:e9:66:55:d4:33:b3:5c:f8:43:20:
+ 78:93:55:16:70:19:32:e6:89:d7:64:eb:bd:48:50:
+ fd:f6:d0:41:03:c2:74:b7:fd:f6:80:cf:5b:c5:ab:
+ a4:d6:95:12:9b:e7:97:13:32:03:e9:d4:ab:43:5b:
+ 16:ed:33:22:64:29:b6:d2:93:ad:2f:6c:d8:3d:b6:
+ f6:1d:0e:34:ee:d2:7d:a9:55:0f:20:f4:fd:29:bb:
+ 91:5b:1c:7d:c6:42:38:6d:42:28:6d:d4:01:fb:cd:
+ 88:97:49:7e:b8:f3:83:f8:b5:98:2f:b3:27:0b:48:
+ 5e:56:e7:4e:a3:33:b3:44:d6:a5:f2:18:94:ed:1c:
+ 1e:a9:95:5c:62:4a:f8:0d:67:51:a9:af:21:d5:f8:
+ 32:9d:79:ba:1a:5f:e5:04:55:4d:13:46:ff:f2:cf:
+ 74:c7:1a:63:6d:c3:1f:17:12:c3:1e:10:3e:60:08:
+ b3:31
+ Exponent: 65537 (0x10001)
+ X509v3 extensions:
+ X509v3 Subject Key Identifier:
+ DD:55:17:13:F6:AC:E8:48:21:CA:EF:B5:AF:D1:00:32:ED:9E:8C:B5
+ X509v3 Key Usage: critical
+ Certificate Sign, CRL Sign
+ X509v3 Basic Constraints: critical
+ CA:TRUE
+ Signature Algorithm: sha256WithRSAEncryption
+ 6f:58:0d:97:43:aa:16:54:3e:bf:a9:df:92:45:3f:85:0b:bb:
+ 56:d3:0c:52:cc:c8:bf:76:67:5e:e6:aa:b3:a7:ef:b9:ac:b4:
+ 10:14:0d:74:7e:3d:6d:ad:d1:7d:d0:9a:a9:a5:ca:18:3b:02:
+ 40:2e:2a:9c:50:14:8b:fe:57:7e:57:5c:11:09:4b:36:45:52:
+ f7:3d:ac:14:fd:44:df:8b:97:23:d4:c3:c1:ee:d4:53:95:fe:
+ 2c:4a:fe:0d:70:aa:bb:8b:2f:2d:cb:32:a3:82:f2:54:df:d8:
+ f2:dd:d7:48:72:ee:4a:a3:29:96:c3:44:ce:6e:b5:92:87:76:
+ a4:bb:f4:92:6c:ce:2c:14:09:66:8e:8d:ad:16:b5:c7:1b:09:
+ 61:3b:e3:20:a2:03:80:8e:ad:7e:51:00:4e:c7:96:86:fb:43:
+ 98:77:7d:28:c7:8f:d8:2a:6e:e7:84:6f:97:41:29:00:16:5e:
+ 4d:e2:13:ea:59:c0:63:67:3a:44:fb:98:fc:04:d3:30:72:a6:
+ f6:87:09:57:ad:76:a6:1d:63:9a:fd:d7:65:c8:78:83:2b:75:
+ 3b:a5:5b:b8:0d:5d:7f:be:23:ae:56:55:94:58:ef:1f:81:8c:
+ 2a:b2:cd:e6:9b:63:9e:18:bc:e5:6b:06:b4:0b:98:4b:28:5e:
+ af:88:58:cb
+SHA1 Fingerprint=8A:5C:8C:EE:A5:03:E6:05:56:BA:D8:1B:D4:F6:C9:B0:ED:E5:2F:E0
diff --git a/luni/src/main/files/cacerts/72fa7371.0 b/luni/src/main/files/cacerts/72fa7371.0
deleted file mode 100644
index d7a34be..0000000
--- a/luni/src/main/files/cacerts/72fa7371.0
+++ /dev/null
@@ -1,54 +0,0 @@
------BEGIN CERTIFICATE-----
-MIIDAjCCAmsCEH3Z/gfPqB63EHln+6eJNMYwDQYJKoZIhvcNAQEFBQAwgcExCzAJ
-BgNVBAYTAlVTMRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE8MDoGA1UECxMzQ2xh
-c3MgMyBQdWJsaWMgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEcy
-MTowOAYDVQQLEzEoYykgMTk5OCBWZXJpU2lnbiwgSW5jLiAtIEZvciBhdXRob3Jp
-emVkIHVzZSBvbmx5MR8wHQYDVQQLExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMB4X
-DTk4MDUxODAwMDAwMFoXDTI4MDgwMTIzNTk1OVowgcExCzAJBgNVBAYTAlVTMRcw
-FQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE8MDoGA1UECxMzQ2xhc3MgMyBQdWJsaWMg
-UHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEcyMTowOAYDVQQLEzEo
-YykgMTk5OCBWZXJpU2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5
-MR8wHQYDVQQLExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMIGfMA0GCSqGSIb3DQEB
-AQUAA4GNADCBiQKBgQDMXtERXVxp0KvTuWpMmR9ZmDCOFoUgRm1HP9SFIIThbbP4
-pO0M8RcPO/mn+SXXwc+EY/J8Y8+iR/LGWzOOZEAEaMGAuWQcRXfH2G71lSk8UOg0
-13gfqLptQ5GVj0VXXn7F+8qkBOvqlzdUMG+7AUcyM83cV5tkaWH4mx0ciU9cZwID
-AQABMA0GCSqGSIb3DQEBBQUAA4GBAFFNzb5cy5gZnBWyATl4Lk0PZ3BwmcYQWpSk
-U01UbSuvDV1Ai2TT1+7eVmGSX6bEHRBhNtMsJzzoKQm5EWR0zLVznxxIqbxhAe7i
-F6YM40AIOw7n60RzKprxaZLvcRTDOaxxp5EJb+RxBrO6WVcmeQD2+A2iMzAo1KpY
-oJ2daZH9
------END CERTIFICATE-----
-Certificate:
- Data:
- Version: 1 (0x0)
- Serial Number:
- 7d:d9:fe:07:cf:a8:1e:b7:10:79:67:fb:a7:89:34:c6
- Signature Algorithm: sha1WithRSAEncryption
- Issuer: C=US, O=VeriSign, Inc., OU=Class 3 Public Primary Certification Authority - G2, OU=(c) 1998 VeriSign, Inc. - For authorized use only, OU=VeriSign Trust Network
- Validity
- Not Before: May 18 00:00:00 1998 GMT
- Not After : Aug 1 23:59:59 2028 GMT
- Subject: C=US, O=VeriSign, Inc., OU=Class 3 Public Primary Certification Authority - G2, OU=(c) 1998 VeriSign, Inc. - For authorized use only, OU=VeriSign Trust Network
- Subject Public Key Info:
- Public Key Algorithm: rsaEncryption
- Public-Key: (1024 bit)
- Modulus:
- 00:cc:5e:d1:11:5d:5c:69:d0:ab:d3:b9:6a:4c:99:
- 1f:59:98:30:8e:16:85:20:46:6d:47:3f:d4:85:20:
- 84:e1:6d:b3:f8:a4:ed:0c:f1:17:0f:3b:f9:a7:f9:
- 25:d7:c1:cf:84:63:f2:7c:63:cf:a2:47:f2:c6:5b:
- 33:8e:64:40:04:68:c1:80:b9:64:1c:45:77:c7:d8:
- 6e:f5:95:29:3c:50:e8:34:d7:78:1f:a8:ba:6d:43:
- 91:95:8f:45:57:5e:7e:c5:fb:ca:a4:04:eb:ea:97:
- 37:54:30:6f:bb:01:47:32:33:cd:dc:57:9b:64:69:
- 61:f8:9b:1d:1c:89:4f:5c:67
- Exponent: 65537 (0x10001)
- Signature Algorithm: sha1WithRSAEncryption
- 51:4d:cd:be:5c:cb:98:19:9c:15:b2:01:39:78:2e:4d:0f:67:
- 70:70:99:c6:10:5a:94:a4:53:4d:54:6d:2b:af:0d:5d:40:8b:
- 64:d3:d7:ee:de:56:61:92:5f:a6:c4:1d:10:61:36:d3:2c:27:
- 3c:e8:29:09:b9:11:64:74:cc:b5:73:9f:1c:48:a9:bc:61:01:
- ee:e2:17:a6:0c:e3:40:08:3b:0e:e7:eb:44:73:2a:9a:f1:69:
- 92:ef:71:14:c3:39:ac:71:a7:91:09:6f:e4:71:06:b3:ba:59:
- 57:26:79:00:f6:f8:0d:a2:33:30:28:d4:aa:58:a0:9d:9d:69:
- 91:fd
-SHA1 Fingerprint=85:37:1C:A6:E5:50:14:3D:CE:28:03:47:1B:DE:3A:09:E8:F8:77:0F
diff --git a/luni/src/main/files/cacerts/74c26bd0.0 b/luni/src/main/files/cacerts/74c26bd0.0
deleted file mode 100644
index 55903f6..0000000
--- a/luni/src/main/files/cacerts/74c26bd0.0
+++ /dev/null
@@ -1,60 +0,0 @@
------BEGIN CERTIFICATE-----
-MIICkDCCAfmgAwIBAgIBATANBgkqhkiG9w0BAQQFADBaMQswCQYDVQQGEwJVUzEc
-MBoGA1UEChMTRXF1aWZheCBTZWN1cmUgSW5jLjEtMCsGA1UEAxMkRXF1aWZheCBT
-ZWN1cmUgR2xvYmFsIGVCdXNpbmVzcyBDQS0xMB4XDTk5MDYyMTA0MDAwMFoXDTIw
-MDYyMTA0MDAwMFowWjELMAkGA1UEBhMCVVMxHDAaBgNVBAoTE0VxdWlmYXggU2Vj
-dXJlIEluYy4xLTArBgNVBAMTJEVxdWlmYXggU2VjdXJlIEdsb2JhbCBlQnVzaW5l
-c3MgQ0EtMTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAuucXkAJlsTRVPEnC
-UdXfp9E3j9HngXNBUmCbnaEXJnitx7HoJpQytd4zjTov2/KaelpzmKNc6fuKcxtc
-58O/gGzNqfTWK8D3+ZmqY6KxRwIP1ORROhI8bIpaVIRw28HFkM9yRcuoWcDNM50/
-o5brhTMhHD4ePmBudpxnhcXIw2ECAwEAAaNmMGQwEQYJYIZIAYb4QgEBBAQDAgAH
-MA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAUvqigdHJQa0S3ySPY+6j/s1dr
-aGwwHQYDVR0OBBYEFL6ooHRyUGtEt8kj2Puo/7NXa2hsMA0GCSqGSIb3DQEBBAUA
-A4GBADDiAVGqx+pf2rnQZQ8w1j7aDRRJbpGTJxQx78T3LUX47Me/okENI7SS+RkA
-Z70Br83gcfxaz2TE4JaY0KNA4gGK7ycH8WUBikQtBmV1UsCGECAhX2xrD2yuCRyv
-8qIYNMR1pHMc8Y3c7635s3a0kr/clRAevsvIO1qEYBlWlKlV
------END CERTIFICATE-----
-Certificate:
- Data:
- Version: 3 (0x2)
- Serial Number: 1 (0x1)
- Signature Algorithm: md5WithRSAEncryption
- Issuer: C=US, O=Equifax Secure Inc., CN=Equifax Secure Global eBusiness CA-1
- Validity
- Not Before: Jun 21 04:00:00 1999 GMT
- Not After : Jun 21 04:00:00 2020 GMT
- Subject: C=US, O=Equifax Secure Inc., CN=Equifax Secure Global eBusiness CA-1
- Subject Public Key Info:
- Public Key Algorithm: rsaEncryption
- Public-Key: (1024 bit)
- Modulus:
- 00:ba:e7:17:90:02:65:b1:34:55:3c:49:c2:51:d5:
- df:a7:d1:37:8f:d1:e7:81:73:41:52:60:9b:9d:a1:
- 17:26:78:ad:c7:b1:e8:26:94:32:b5:de:33:8d:3a:
- 2f:db:f2:9a:7a:5a:73:98:a3:5c:e9:fb:8a:73:1b:
- 5c:e7:c3:bf:80:6c:cd:a9:f4:d6:2b:c0:f7:f9:99:
- aa:63:a2:b1:47:02:0f:d4:e4:51:3a:12:3c:6c:8a:
- 5a:54:84:70:db:c1:c5:90:cf:72:45:cb:a8:59:c0:
- cd:33:9d:3f:a3:96:eb:85:33:21:1c:3e:1e:3e:60:
- 6e:76:9c:67:85:c5:c8:c3:61
- Exponent: 65537 (0x10001)
- X509v3 extensions:
- Netscape Cert Type:
- SSL CA, S/MIME CA, Object Signing CA
- X509v3 Basic Constraints: critical
- CA:TRUE
- X509v3 Authority Key Identifier:
- keyid:BE:A8:A0:74:72:50:6B:44:B7:C9:23:D8:FB:A8:FF:B3:57:6B:68:6C
-
- X509v3 Subject Key Identifier:
- BE:A8:A0:74:72:50:6B:44:B7:C9:23:D8:FB:A8:FF:B3:57:6B:68:6C
- Signature Algorithm: md5WithRSAEncryption
- 30:e2:01:51:aa:c7:ea:5f:da:b9:d0:65:0f:30:d6:3e:da:0d:
- 14:49:6e:91:93:27:14:31:ef:c4:f7:2d:45:f8:ec:c7:bf:a2:
- 41:0d:23:b4:92:f9:19:00:67:bd:01:af:cd:e0:71:fc:5a:cf:
- 64:c4:e0:96:98:d0:a3:40:e2:01:8a:ef:27:07:f1:65:01:8a:
- 44:2d:06:65:75:52:c0:86:10:20:21:5f:6c:6b:0f:6c:ae:09:
- 1c:af:f2:a2:18:34:c4:75:a4:73:1c:f1:8d:dc:ef:ad:f9:b3:
- 76:b4:92:bf:dc:95:10:1e:be:cb:c8:3b:5a:84:60:19:56:94:
- a9:55
-SHA1 Fingerprint=7E:78:4A:10:1C:82:65:CC:2D:E1:F1:6D:47:B4:40:CA:D9:0A:19:45
diff --git a/luni/src/main/files/cacerts/7a481e66.0 b/luni/src/main/files/cacerts/7a481e66.0
deleted file mode 100644
index d40dfea..0000000
--- a/luni/src/main/files/cacerts/7a481e66.0
+++ /dev/null
@@ -1,91 +0,0 @@
------BEGIN CERTIFICATE-----
-MIIEqjCCA5KgAwIBAgIOSkcAAQAC5aBd1j8AUb8wDQYJKoZIhvcNAQEFBQAwdjEL
-MAkGA1UEBhMCREUxHDAaBgNVBAoTE1RDIFRydXN0Q2VudGVyIEdtYkgxIjAgBgNV
-BAsTGVRDIFRydXN0Q2VudGVyIENsYXNzIDMgQ0ExJTAjBgNVBAMTHFRDIFRydXN0
-Q2VudGVyIENsYXNzIDMgQ0EgSUkwHhcNMDYwMTEyMTQ0MTU3WhcNMjUxMjMxMjI1
-OTU5WjB2MQswCQYDVQQGEwJERTEcMBoGA1UEChMTVEMgVHJ1c3RDZW50ZXIgR21i
-SDEiMCAGA1UECxMZVEMgVHJ1c3RDZW50ZXIgQ2xhc3MgMyBDQTElMCMGA1UEAxMc
-VEMgVHJ1c3RDZW50ZXIgQ2xhc3MgMyBDQSBJSTCCASIwDQYJKoZIhvcNAQEBBQAD
-ggEPADCCAQoCggEBALTgu1G7OVyLBMVMeRwjhjEQY0NVJz/GRcekPewJDRoeIMJW
-Ht4bNwcwIi9v8Qbxq63WyKthoy9DxLCyLfzDlml7forkzMA5EpBCYMnMNWju2l+Q
-Vl/NHE1bWEnrDgFPZPosPIlY2C8u4rBo6SI7dYnWRBpl8huXJh0obazovVkdKyT2
-1oQDZogkAHhg8fir/gKya/si+zXmFtGt9i4S5Po1auUZuV3bOx4a+9P/FRQI2Alq
-ukWdFHlgfa9Aigdzs5OW03Q0jTo3Kd5c7PXuLjHCINy+8U9/I1LZW+Jk2ZyqBwi1
-Rb3R0DHBq1SfqdLDYmAD8bs5SpJKPQq5ncWg/jcCAwEAAaOCATQwggEwMA8GA1Ud
-EwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBTUovyfs8PYA9NX
-XAek0CSnwPIA1DCB7QYDVR0fBIHlMIHiMIHfoIHcoIHZhjVodHRwOi8vd3d3LnRy
-dXN0Y2VudGVyLmRlL2NybC92Mi90Y19jbGFzc18zX2NhX0lJLmNybIaBn2xkYXA6
-Ly93d3cudHJ1c3RjZW50ZXIuZGUvQ049VEMlMjBUcnVzdENlbnRlciUyMENsYXNz
-JTIwMyUyMENBJTIwSUksTz1UQyUyMFRydXN0Q2VudGVyJTIwR21iSCxPVT1yb290
-Y2VydHMsREM9dHJ1c3RjZW50ZXIsREM9ZGU/Y2VydGlmaWNhdGVSZXZvY2F0aW9u
-TGlzdD9iYXNlPzANBgkqhkiG9w0BAQUFAAOCAQEANmDkcPcGIEPZIxpC8vijsrlN
-irTzwppVMXzEO2eatN9NDoqTSheLG43KieHPOh6sHfGcMrSOWXaiQYUlN6AT0PV8
-TtXqluJucsG7Kv5sbviRmEb8yRtXW+rIGjs/sFGYPAfaLFkB2otE6OF0/ado3VS6
-g0bsyEa1+K+XwDsJHI/OcpY9M1ZwvJbL2NV9IJqDnxrcOfHFcqMRA/07QlIp2+gB
-95tejNaNhk4Z+rwcvsUhpYeeeC422wlxo3I0+GzjBgnyXlal092Y+tTmBvTwtiBj
-S+opvaqCZh77gaqnN60TGOaSw4HBM7uIHqHn4rS9MWwOUT1v+5ZWgOI2F9Hc5A==
------END CERTIFICATE-----
-Certificate:
- Data:
- Version: 3 (0x2)
- Serial Number:
- 4a:47:00:01:00:02:e5:a0:5d:d6:3f:00:51:bf
- Signature Algorithm: sha1WithRSAEncryption
- Issuer: C=DE, O=TC TrustCenter GmbH, OU=TC TrustCenter Class 3 CA, CN=TC TrustCenter Class 3 CA II
- Validity
- Not Before: Jan 12 14:41:57 2006 GMT
- Not After : Dec 31 22:59:59 2025 GMT
- Subject: C=DE, O=TC TrustCenter GmbH, OU=TC TrustCenter Class 3 CA, CN=TC TrustCenter Class 3 CA II
- Subject Public Key Info:
- Public Key Algorithm: rsaEncryption
- Public-Key: (2048 bit)
- Modulus:
- 00:b4:e0:bb:51:bb:39:5c:8b:04:c5:4c:79:1c:23:
- 86:31:10:63:43:55:27:3f:c6:45:c7:a4:3d:ec:09:
- 0d:1a:1e:20:c2:56:1e:de:1b:37:07:30:22:2f:6f:
- f1:06:f1:ab:ad:d6:c8:ab:61:a3:2f:43:c4:b0:b2:
- 2d:fc:c3:96:69:7b:7e:8a:e4:cc:c0:39:12:90:42:
- 60:c9:cc:35:68:ee:da:5f:90:56:5f:cd:1c:4d:5b:
- 58:49:eb:0e:01:4f:64:fa:2c:3c:89:58:d8:2f:2e:
- e2:b0:68:e9:22:3b:75:89:d6:44:1a:65:f2:1b:97:
- 26:1d:28:6d:ac:e8:bd:59:1d:2b:24:f6:d6:84:03:
- 66:88:24:00:78:60:f1:f8:ab:fe:02:b2:6b:fb:22:
- fb:35:e6:16:d1:ad:f6:2e:12:e4:fa:35:6a:e5:19:
- b9:5d:db:3b:1e:1a:fb:d3:ff:15:14:08:d8:09:6a:
- ba:45:9d:14:79:60:7d:af:40:8a:07:73:b3:93:96:
- d3:74:34:8d:3a:37:29:de:5c:ec:f5:ee:2e:31:c2:
- 20:dc:be:f1:4f:7f:23:52:d9:5b:e2:64:d9:9c:aa:
- 07:08:b5:45:bd:d1:d0:31:c1:ab:54:9f:a9:d2:c3:
- 62:60:03:f1:bb:39:4a:92:4a:3d:0a:b9:9d:c5:a0:
- fe:37
- Exponent: 65537 (0x10001)
- X509v3 extensions:
- X509v3 Basic Constraints: critical
- CA:TRUE
- X509v3 Key Usage: critical
- Certificate Sign, CRL Sign
- X509v3 Subject Key Identifier:
- D4:A2:FC:9F:B3:C3:D8:03:D3:57:5C:07:A4:D0:24:A7:C0:F2:00:D4
- X509v3 CRL Distribution Points:
-
- Full Name:
- URI:http://www.trustcenter.de/crl/v2/tc_class_3_ca_II.crl
- URI:ldap://www.trustcenter.de/CN=TC%20TrustCenter%20Class%203%20CA%20II,O=TC%20TrustCenter%20GmbH,OU=rootcerts,DC=trustcenter,DC=de?certificateRevocationList?base?
-
- Signature Algorithm: sha1WithRSAEncryption
- 36:60:e4:70:f7:06:20:43:d9:23:1a:42:f2:f8:a3:b2:b9:4d:
- 8a:b4:f3:c2:9a:55:31:7c:c4:3b:67:9a:b4:df:4d:0e:8a:93:
- 4a:17:8b:1b:8d:ca:89:e1:cf:3a:1e:ac:1d:f1:9c:32:b4:8e:
- 59:76:a2:41:85:25:37:a0:13:d0:f5:7c:4e:d5:ea:96:e2:6e:
- 72:c1:bb:2a:fe:6c:6e:f8:91:98:46:fc:c9:1b:57:5b:ea:c8:
- 1a:3b:3f:b0:51:98:3c:07:da:2c:59:01:da:8b:44:e8:e1:74:
- fd:a7:68:dd:54:ba:83:46:ec:c8:46:b5:f8:af:97:c0:3b:09:
- 1c:8f:ce:72:96:3d:33:56:70:bc:96:cb:d8:d5:7d:20:9a:83:
- 9f:1a:dc:39:f1:c5:72:a3:11:03:fd:3b:42:52:29:db:e8:01:
- f7:9b:5e:8c:d6:8d:86:4e:19:fa:bc:1c:be:c5:21:a5:87:9e:
- 78:2e:36:db:09:71:a3:72:34:f8:6c:e3:06:09:f2:5e:56:a5:
- d3:dd:98:fa:d4:e6:06:f4:f0:b6:20:63:4b:ea:29:bd:aa:82:
- 66:1e:fb:81:aa:a7:37:ad:13:18:e6:92:c3:81:c1:33:bb:88:
- 1e:a1:e7:e2:b4:bd:31:6c:0e:51:3d:6f:fb:96:56:80:e2:36:
- 17:d1:dc:e4
-SHA1 Fingerprint=80:25:EF:F4:6E:70:C8:D4:72:24:65:84:FE:40:3B:8A:8D:6A:DB:F5
diff --git a/luni/src/main/files/cacerts/9282e51c.0 b/luni/src/main/files/cacerts/9282e51c.0
new file mode 100644
index 0000000..f2a9f94
--- /dev/null
+++ b/luni/src/main/files/cacerts/9282e51c.0
@@ -0,0 +1,123 @@
+-----BEGIN CERTIFICATE-----
+MIIFjTCCA3WgAwIBAgIEGErM1jANBgkqhkiG9w0BAQsFADBWMQswCQYDVQQGEwJD
+TjEwMC4GA1UECgwnQ2hpbmEgRmluYW5jaWFsIENlcnRpZmljYXRpb24gQXV0aG9y
+aXR5MRUwEwYDVQQDDAxDRkNBIEVWIFJPT1QwHhcNMTIwODA4MDMwNzAxWhcNMjkx
+MjMxMDMwNzAxWjBWMQswCQYDVQQGEwJDTjEwMC4GA1UECgwnQ2hpbmEgRmluYW5j
+aWFsIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MRUwEwYDVQQDDAxDRkNBIEVWIFJP
+T1QwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDXXWvNED8fBVnVBU03
+sQ7smCuOFR36k0sXgiFxEFLXUWRwFsJVaU2OFW2fvwwbwuCjZ9YMrM8irq93VCpL
+TIpTUnrD7i7es3ElweldPe6hL6P3KjzJIx1qqx2hp/Hz7KDVRM8Vz3IvHWOX6Jn5
+/ZOkVIBMUtRSqy5J35DNuF++P96hyk0g1CXohClTt7GIH//62pCfCqktQT+x8Rgp
+7hZZLDRJGqgG16iI0gNyejLi6mhNbiyWZXvKWfry4t3uMCz7zEasxGPrb382KzRz
+EpR/38wmnvFyXVBlWY9ps4deMm/DGIq1lY+wejfeWkU7xzbh72fROdOXW3NiGUgt
+hxwG+3SYIElz8AXSG7Ggo7cbcNOIabla1jj0Ytwli3i/+Oh+uFzJlU9fpy25IGvP
+a931DfSCt/SyZi4QKPaXWnuWFo8BGS1sbn85WAZkgwGDg8NNkt0yxoekN+kWzqot
+aK8KgWU6cMGbrU1tVMoqLUuFG7OA5nBFDWteNfB/O7ic5ARwiRIlk9oKmSJgamNg
+TnYGmE69g60dWIolhdLHZR4tjsbftsbhf4oEIRUpdPA+nJCdDC7xij5aqgwJHsfV
+PKPtl8MeNPo4+QgO48BdK4PRVmrJtqhUUy54Mmc9gn900PvhtgVguXDbjgv5E1hv
+cWAQUhC5wUEJ73IfZzF4/5YFjQIDAQABo2MwYTAfBgNVHSMEGDAWgBTj/i39KNAL
+tbq2osS/BqoFjJP7LzAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAd
+BgNVHQ4EFgQU4/4t/SjQC7W6tqLEvwaqBYyT+y8wDQYJKoZIhvcNAQELBQADggIB
+ACXGumvrh8vegjmWPfBEp2uEcwPenStPuiB/vHiyz5ewG5zz13ku9Ui20vsXiObT
+ej/tUxPQ4i9qecsAIyjmHjdXNYmEwnZPNDatZ8POQQaIxffu2Bq41gt/UP+TqhdL
+jOztUmCypAbqTuv0axn96/Ua4CUqmtzHQTb3yHQFhDmVOdYLO6Qn+gjYXB74BGBS
+ESgoA//vU2YApUo0FmZ8/Qmkrp5nGm9BC2sGE5uPhnEFtC+NiWYzKXZUmhH4J/qy
+P5Hgzg0b8zAarb8iXRvTvyUFTeGSGn+ZnzxEk8rUQElsgIfXBDrDMlI1Dlb4pd19
+xIsNER9Tyx6yF7Zod1rg1MvIB671Oi6ON7fQAUtDKXeMOZePglr4UeWJoBjnaH9d
+Ci77o0cOPaYjesYBx4/IXr9tgFa+iiS6M+qf4TIRnvHST4D2G0CvOJ4RUHlzEhLN
+5mydLIhyPDCBBpEi6lmt2hkuIsKNuYyH4Ga8cyNfIWRjgEj1oDwYPZTISEEdQLpe
+/v5WOaHIz16eGWRGENoXkbcFgKyLmZJ956LYBws2J+dIeWCKw9cTXPhyQN9Ky8+Z
+AAoACxGV2lZFA4gKn2fQ1XmxqI1AbQ3CekD6819kR5LLU7m7Wc5P/dAVUwHY3+vZ
+5nbv0CO7O6l5s9UCKc2Jo5YPSjXnTkLAdc0Hz+Ys63su
+-----END CERTIFICATE-----
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number: 407555286 (0x184accd6)
+ Signature Algorithm: sha256WithRSAEncryption
+ Issuer: C=CN, O=China Financial Certification Authority, CN=CFCA EV ROOT
+ Validity
+ Not Before: Aug 8 03:07:01 2012 GMT
+ Not After : Dec 31 03:07:01 2029 GMT
+ Subject: C=CN, O=China Financial Certification Authority, CN=CFCA EV ROOT
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ Public-Key: (4096 bit)
+ Modulus:
+ 00:d7:5d:6b:cd:10:3f:1f:05:59:d5:05:4d:37:b1:
+ 0e:ec:98:2b:8e:15:1d:fa:93:4b:17:82:21:71:10:
+ 52:d7:51:64:70:16:c2:55:69:4d:8e:15:6d:9f:bf:
+ 0c:1b:c2:e0:a3:67:d6:0c:ac:cf:22:ae:af:77:54:
+ 2a:4b:4c:8a:53:52:7a:c3:ee:2e:de:b3:71:25:c1:
+ e9:5d:3d:ee:a1:2f:a3:f7:2a:3c:c9:23:1d:6a:ab:
+ 1d:a1:a7:f1:f3:ec:a0:d5:44:cf:15:cf:72:2f:1d:
+ 63:97:e8:99:f9:fd:93:a4:54:80:4c:52:d4:52:ab:
+ 2e:49:df:90:cd:b8:5f:be:3f:de:a1:ca:4d:20:d4:
+ 25:e8:84:29:53:b7:b1:88:1f:ff:fa:da:90:9f:0a:
+ a9:2d:41:3f:b1:f1:18:29:ee:16:59:2c:34:49:1a:
+ a8:06:d7:a8:88:d2:03:72:7a:32:e2:ea:68:4d:6e:
+ 2c:96:65:7b:ca:59:fa:f2:e2:dd:ee:30:2c:fb:cc:
+ 46:ac:c4:63:eb:6f:7f:36:2b:34:73:12:94:7f:df:
+ cc:26:9e:f1:72:5d:50:65:59:8f:69:b3:87:5e:32:
+ 6f:c3:18:8a:b5:95:8f:b0:7a:37:de:5a:45:3b:c7:
+ 36:e1:ef:67:d1:39:d3:97:5b:73:62:19:48:2d:87:
+ 1c:06:fb:74:98:20:49:73:f0:05:d2:1b:b1:a0:a3:
+ b7:1b:70:d3:88:69:b9:5a:d6:38:f4:62:dc:25:8b:
+ 78:bf:f8:e8:7e:b8:5c:c9:95:4f:5f:a7:2d:b9:20:
+ 6b:cf:6b:dd:f5:0d:f4:82:b7:f4:b2:66:2e:10:28:
+ f6:97:5a:7b:96:16:8f:01:19:2d:6c:6e:7f:39:58:
+ 06:64:83:01:83:83:c3:4d:92:dd:32:c6:87:a4:37:
+ e9:16:ce:aa:2d:68:af:0a:81:65:3a:70:c1:9b:ad:
+ 4d:6d:54:ca:2a:2d:4b:85:1b:b3:80:e6:70:45:0d:
+ 6b:5e:35:f0:7f:3b:b8:9c:e4:04:70:89:12:25:93:
+ da:0a:99:22:60:6a:63:60:4e:76:06:98:4e:bd:83:
+ ad:1d:58:8a:25:85:d2:c7:65:1e:2d:8e:c6:df:b6:
+ c6:e1:7f:8a:04:21:15:29:74:f0:3e:9c:90:9d:0c:
+ 2e:f1:8a:3e:5a:aa:0c:09:1e:c7:d5:3c:a3:ed:97:
+ c3:1e:34:fa:38:f9:08:0e:e3:c0:5d:2b:83:d1:56:
+ 6a:c9:b6:a8:54:53:2e:78:32:67:3d:82:7f:74:d0:
+ fb:e1:b6:05:60:b9:70:db:8e:0b:f9:13:58:6f:71:
+ 60:10:52:10:b9:c1:41:09:ef:72:1f:67:31:78:ff:
+ 96:05:8d
+ Exponent: 65537 (0x10001)
+ X509v3 extensions:
+ X509v3 Authority Key Identifier:
+ keyid:E3:FE:2D:FD:28:D0:0B:B5:BA:B6:A2:C4:BF:06:AA:05:8C:93:FB:2F
+
+ X509v3 Basic Constraints: critical
+ CA:TRUE
+ X509v3 Key Usage: critical
+ Certificate Sign, CRL Sign
+ X509v3 Subject Key Identifier:
+ E3:FE:2D:FD:28:D0:0B:B5:BA:B6:A2:C4:BF:06:AA:05:8C:93:FB:2F
+ Signature Algorithm: sha256WithRSAEncryption
+ 25:c6:ba:6b:eb:87:cb:de:82:39:96:3d:f0:44:a7:6b:84:73:
+ 03:de:9d:2b:4f:ba:20:7f:bc:78:b2:cf:97:b0:1b:9c:f3:d7:
+ 79:2e:f5:48:b6:d2:fb:17:88:e6:d3:7a:3f:ed:53:13:d0:e2:
+ 2f:6a:79:cb:00:23:28:e6:1e:37:57:35:89:84:c2:76:4f:34:
+ 36:ad:67:c3:ce:41:06:88:c5:f7:ee:d8:1a:b8:d6:0b:7f:50:
+ ff:93:aa:17:4b:8c:ec:ed:52:60:b2:a4:06:ea:4e:eb:f4:6b:
+ 19:fd:eb:f5:1a:e0:25:2a:9a:dc:c7:41:36:f7:c8:74:05:84:
+ 39:95:39:d6:0b:3b:a4:27:fa:08:d8:5c:1e:f8:04:60:52:11:
+ 28:28:03:ff:ef:53:66:00:a5:4a:34:16:66:7c:fd:09:a4:ae:
+ 9e:67:1a:6f:41:0b:6b:06:13:9b:8f:86:71:05:b4:2f:8d:89:
+ 66:33:29:76:54:9a:11:f8:27:fa:b2:3f:91:e0:ce:0d:1b:f3:
+ 30:1a:ad:bf:22:5d:1b:d3:bf:25:05:4d:e1:92:1a:7f:99:9f:
+ 3c:44:93:ca:d4:40:49:6c:80:87:d7:04:3a:c3:32:52:35:0e:
+ 56:f8:a5:dd:7d:c4:8b:0d:11:1f:53:cb:1e:b2:17:b6:68:77:
+ 5a:e0:d4:cb:c8:07:ae:f5:3a:2e:8e:37:b7:d0:01:4b:43:29:
+ 77:8c:39:97:8f:82:5a:f8:51:e5:89:a0:18:e7:68:7f:5d:0a:
+ 2e:fb:a3:47:0e:3d:a6:23:7a:c6:01:c7:8f:c8:5e:bf:6d:80:
+ 56:be:8a:24:ba:33:ea:9f:e1:32:11:9e:f1:d2:4f:80:f6:1b:
+ 40:af:38:9e:11:50:79:73:12:12:cd:e6:6c:9d:2c:88:72:3c:
+ 30:81:06:91:22:ea:59:ad:da:19:2e:22:c2:8d:b9:8c:87:e0:
+ 66:bc:73:23:5f:21:64:63:80:48:f5:a0:3c:18:3d:94:c8:48:
+ 41:1d:40:ba:5e:fe:fe:56:39:a1:c8:cf:5e:9e:19:64:46:10:
+ da:17:91:b7:05:80:ac:8b:99:92:7d:e7:a2:d8:07:0b:36:27:
+ e7:48:79:60:8a:c3:d7:13:5c:f8:72:40:df:4a:cb:cf:99:00:
+ 0a:00:0b:11:95:da:56:45:03:88:0a:9f:67:d0:d5:79:b1:a8:
+ 8d:40:6d:0d:c2:7a:40:fa:f3:5f:64:47:92:cb:53:b9:bb:59:
+ ce:4f:fd:d0:15:53:01:d8:df:eb:d9:e6:76:ef:d0:23:bb:3b:
+ a9:79:b3:d5:02:29:cd:89:a3:96:0f:4a:35:e7:4e:42:c0:75:
+ cd:07:cf:e6:2c:eb:7b:2e
+SHA1 Fingerprint=E2:B8:29:4B:55:84:AB:6B:58:C2:90:46:6C:AC:3F:B8:39:8F:84:83
diff --git a/luni/src/main/files/cacerts/bda4cc84.0 b/luni/src/main/files/cacerts/bda4cc84.0
deleted file mode 100644
index 4dac2ad..0000000
--- a/luni/src/main/files/cacerts/bda4cc84.0
+++ /dev/null
@@ -1,82 +0,0 @@
------BEGIN CERTIFICATE-----
-MIIDpDCCAoygAwIBAgIBATANBgkqhkiG9w0BAQUFADBjMQswCQYDVQQGEwJVUzEc
-MBoGA1UEChMTQW1lcmljYSBPbmxpbmUgSW5jLjE2MDQGA1UEAxMtQW1lcmljYSBP
-bmxpbmUgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAxMB4XDTAyMDUyODA2
-MDAwMFoXDTM3MTExOTIwNDMwMFowYzELMAkGA1UEBhMCVVMxHDAaBgNVBAoTE0Ft
-ZXJpY2EgT25saW5lIEluYy4xNjA0BgNVBAMTLUFtZXJpY2EgT25saW5lIFJvb3Qg
-Q2VydGlmaWNhdGlvbiBBdXRob3JpdHkgMTCCASIwDQYJKoZIhvcNAQEBBQADggEP
-ADCCAQoCggEBAKgv6KRpBgNHw+kqmP8ZonCaxlCyfqXfaE0bfA+2l2h9LaaLl+lk
-hsmj76CGv2BlnEtUiMJIxUo5vxTjWVXlGbR0yLQFOVwWpeKVBeASrlmLojNoWBym
-1BW32J/X3HGrfpq/m44zDyL9Hy7nBzbvYjnF3cu6JRQj3gzGPTzOggjmZj7aUTsW
-OqMFf6Dch9Wc/HKpoH145LcxVR5lu9RhsCFg7RAycsWSJR74kEoYeEfffjA3PlAb
-2xzTa5qGUwew76wGePiEmf4hjUyAtgyC9mZweRrTT6PP8c9GsEsPPt2IYriMqQko
-O3rHl+Ee5fSfwMCuJKDIodkP1nsmgmkyPacCAwEAAaNjMGEwDwYDVR0TAQH/BAUw
-AwEB/zAdBgNVHQ4EFgQUAK3Zo/Z59m50qX8zPYEX10zPM94wHwYDVR0jBBgwFoAU
-AK3Zo/Z59m50qX8zPYEX10zPM94wDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3DQEB
-BQUAA4IBAQB8itEfGDeC4Liwo+1WlchiYZwFos3CYiZhzRAW18y0ZTTQEYqtqKkF
-Zu90821fnZmv9ov761KyBZiibyrFVL0lvV+uyIbqRizBs73B6UlwGBaXCBOMIOAb
-LjpHyx7kADCVW/RFo8AasAFOq73AI25jP4BKxQft3OJvx8Fi8eNy1gTIdGcL+oir
-oQHIb/AUr9KZzVGTfu0uOMe9zkZQPXLjeSWdm4grECDdpbgyn43gKd8hdIaC2y+C
-MMbHNYaz+ZZfRtsMRf3zUMNvxsNIrUam4SdHCh0Om7bCd39j8uB9Gr784N/Xx6ds
-sPmuujz9dLQR6FgNgLzTqIA6me11zEZ7
------END CERTIFICATE-----
-Certificate:
- Data:
- Version: 3 (0x2)
- Serial Number: 1 (0x1)
- Signature Algorithm: sha1WithRSAEncryption
- Issuer: C=US, O=America Online Inc., CN=America Online Root Certification Authority 1
- Validity
- Not Before: May 28 06:00:00 2002 GMT
- Not After : Nov 19 20:43:00 2037 GMT
- Subject: C=US, O=America Online Inc., CN=America Online Root Certification Authority 1
- Subject Public Key Info:
- Public Key Algorithm: rsaEncryption
- Public-Key: (2048 bit)
- Modulus:
- 00:a8:2f:e8:a4:69:06:03:47:c3:e9:2a:98:ff:19:
- a2:70:9a:c6:50:b2:7e:a5:df:68:4d:1b:7c:0f:b6:
- 97:68:7d:2d:a6:8b:97:e9:64:86:c9:a3:ef:a0:86:
- bf:60:65:9c:4b:54:88:c2:48:c5:4a:39:bf:14:e3:
- 59:55:e5:19:b4:74:c8:b4:05:39:5c:16:a5:e2:95:
- 05:e0:12:ae:59:8b:a2:33:68:58:1c:a6:d4:15:b7:
- d8:9f:d7:dc:71:ab:7e:9a:bf:9b:8e:33:0f:22:fd:
- 1f:2e:e7:07:36:ef:62:39:c5:dd:cb:ba:25:14:23:
- de:0c:c6:3d:3c:ce:82:08:e6:66:3e:da:51:3b:16:
- 3a:a3:05:7f:a0:dc:87:d5:9c:fc:72:a9:a0:7d:78:
- e4:b7:31:55:1e:65:bb:d4:61:b0:21:60:ed:10:32:
- 72:c5:92:25:1e:f8:90:4a:18:78:47:df:7e:30:37:
- 3e:50:1b:db:1c:d3:6b:9a:86:53:07:b0:ef:ac:06:
- 78:f8:84:99:fe:21:8d:4c:80:b6:0c:82:f6:66:70:
- 79:1a:d3:4f:a3:cf:f1:cf:46:b0:4b:0f:3e:dd:88:
- 62:b8:8c:a9:09:28:3b:7a:c7:97:e1:1e:e5:f4:9f:
- c0:c0:ae:24:a0:c8:a1:d9:0f:d6:7b:26:82:69:32:
- 3d:a7
- Exponent: 65537 (0x10001)
- X509v3 extensions:
- X509v3 Basic Constraints: critical
- CA:TRUE
- X509v3 Subject Key Identifier:
- 00:AD:D9:A3:F6:79:F6:6E:74:A9:7F:33:3D:81:17:D7:4C:CF:33:DE
- X509v3 Authority Key Identifier:
- keyid:00:AD:D9:A3:F6:79:F6:6E:74:A9:7F:33:3D:81:17:D7:4C:CF:33:DE
-
- X509v3 Key Usage: critical
- Digital Signature, Certificate Sign, CRL Sign
- Signature Algorithm: sha1WithRSAEncryption
- 7c:8a:d1:1f:18:37:82:e0:b8:b0:a3:ed:56:95:c8:62:61:9c:
- 05:a2:cd:c2:62:26:61:cd:10:16:d7:cc:b4:65:34:d0:11:8a:
- ad:a8:a9:05:66:ef:74:f3:6d:5f:9d:99:af:f6:8b:fb:eb:52:
- b2:05:98:a2:6f:2a:c5:54:bd:25:bd:5f:ae:c8:86:ea:46:2c:
- c1:b3:bd:c1:e9:49:70:18:16:97:08:13:8c:20:e0:1b:2e:3a:
- 47:cb:1e:e4:00:30:95:5b:f4:45:a3:c0:1a:b0:01:4e:ab:bd:
- c0:23:6e:63:3f:80:4a:c5:07:ed:dc:e2:6f:c7:c1:62:f1:e3:
- 72:d6:04:c8:74:67:0b:fa:88:ab:a1:01:c8:6f:f0:14:af:d2:
- 99:cd:51:93:7e:ed:2e:38:c7:bd:ce:46:50:3d:72:e3:79:25:
- 9d:9b:88:2b:10:20:dd:a5:b8:32:9f:8d:e0:29:df:21:74:86:
- 82:db:2f:82:30:c6:c7:35:86:b3:f9:96:5f:46:db:0c:45:fd:
- f3:50:c3:6f:c6:c3:48:ad:46:a6:e1:27:47:0a:1d:0e:9b:b6:
- c2:77:7f:63:f2:e0:7d:1a:be:fc:e0:df:d7:c7:a7:6c:b0:f9:
- ae:ba:3c:fd:74:b4:11:e8:58:0d:80:bc:d3:a8:80:3a:99:ed:
- 75:cc:46:7b
-SHA1 Fingerprint=39:21:C1:15:C1:5D:0E:CA:5C:CB:5B:C4:F0:7D:21:D8:05:0B:56:6A
diff --git a/luni/src/main/files/cacerts/c33a80d4.0 b/luni/src/main/files/cacerts/c33a80d4.0
deleted file mode 100644
index 8225654..0000000
--- a/luni/src/main/files/cacerts/c33a80d4.0
+++ /dev/null
@@ -1,58 +0,0 @@
------BEGIN CERTIFICATE-----
-MIIDNjCCAp+gAwIBAgIQNhIilsXjOKUgodJfTNcJVDANBgkqhkiG9w0BAQUFADCB
-zjELMAkGA1UEBhMCWkExFTATBgNVBAgTDFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJ
-Q2FwZSBUb3duMR0wGwYDVQQKExRUaGF3dGUgQ29uc3VsdGluZyBjYzEoMCYGA1UE
-CxMfQ2VydGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjEhMB8GA1UEAxMYVGhh
-d3RlIFByZW1pdW0gU2VydmVyIENBMSgwJgYJKoZIhvcNAQkBFhlwcmVtaXVtLXNl
-cnZlckB0aGF3dGUuY29tMB4XDTk2MDgwMTAwMDAwMFoXDTIxMDEwMTIzNTk1OVow
-gc4xCzAJBgNVBAYTAlpBMRUwEwYDVQQIEwxXZXN0ZXJuIENhcGUxEjAQBgNVBAcT
-CUNhcGUgVG93bjEdMBsGA1UEChMUVGhhd3RlIENvbnN1bHRpbmcgY2MxKDAmBgNV
-BAsTH0NlcnRpZmljYXRpb24gU2VydmljZXMgRGl2aXNpb24xITAfBgNVBAMTGFRo
-YXd0ZSBQcmVtaXVtIFNlcnZlciBDQTEoMCYGCSqGSIb3DQEJARYZcHJlbWl1bS1z
-ZXJ2ZXJAdGhhd3RlLmNvbTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA0jY2
-aovXwlue2oFBYo847kkEVdbQ7xwblRZH7xhINTpS9CtqBo87L+pW46+GjZ4X9560
-ZXUCTe/LCaIhUdib0GfQug2SBhRz1JPLlyoAnFxODLz6FVL88kRu2hFKbgifLy3j
-+ao6hnO2RlNYyIkFvYMRuHM/qgeN9EJN50CdHDcCAwEAAaMTMBEwDwYDVR0TAQH/
-BAUwAwEB/zANBgkqhkiG9w0BAQUFAAOBgQBlkKyID1bZ5jA01CbH0FDxkt5r1DmI
-CSLGpmODA/eZd9iy5Ri4XWPz1HP7bJyZePFLeH0ZJMMrAoT4vCLZiiLXoPxx7JGH
-IPG47LHlVYCsPVLIOQ7C8MAFT9aCdYy9X9LcdpoFEsmvcsPcJX6kTY4XpeCHf+Ga
-WuFg3GQjPEIuTQ==
------END CERTIFICATE-----
-Certificate:
- Data:
- Version: 3 (0x2)
- Serial Number:
- 36:12:22:96:c5:e3:38:a5:20:a1:d2:5f:4c:d7:09:54
- Signature Algorithm: sha1WithRSAEncryption
- Issuer: C=ZA, ST=Western Cape, L=Cape Town, O=Thawte Consulting cc, OU=Certification Services Division, CN=Thawte Premium Server CA/emailAddress=premium-server@thawte.com
- Validity
- Not Before: Aug 1 00:00:00 1996 GMT
- Not After : Jan 1 23:59:59 2021 GMT
- Subject: C=ZA, ST=Western Cape, L=Cape Town, O=Thawte Consulting cc, OU=Certification Services Division, CN=Thawte Premium Server CA/emailAddress=premium-server@thawte.com
- Subject Public Key Info:
- Public Key Algorithm: rsaEncryption
- Public-Key: (1024 bit)
- Modulus:
- 00:d2:36:36:6a:8b:d7:c2:5b:9e:da:81:41:62:8f:
- 38:ee:49:04:55:d6:d0:ef:1c:1b:95:16:47:ef:18:
- 48:35:3a:52:f4:2b:6a:06:8f:3b:2f:ea:56:e3:af:
- 86:8d:9e:17:f7:9e:b4:65:75:02:4d:ef:cb:09:a2:
- 21:51:d8:9b:d0:67:d0:ba:0d:92:06:14:73:d4:93:
- cb:97:2a:00:9c:5c:4e:0c:bc:fa:15:52:fc:f2:44:
- 6e:da:11:4a:6e:08:9f:2f:2d:e3:f9:aa:3a:86:73:
- b6:46:53:58:c8:89:05:bd:83:11:b8:73:3f:aa:07:
- 8d:f4:42:4d:e7:40:9d:1c:37
- Exponent: 65537 (0x10001)
- X509v3 extensions:
- X509v3 Basic Constraints: critical
- CA:TRUE
- Signature Algorithm: sha1WithRSAEncryption
- 65:90:ac:88:0f:56:d9:e6:30:34:d4:26:c7:d0:50:f1:92:de:
- 6b:d4:39:88:09:22:c6:a6:63:83:03:f7:99:77:d8:b2:e5:18:
- b8:5d:63:f3:d4:73:fb:6c:9c:99:78:f1:4b:78:7d:19:24:c3:
- 2b:02:84:f8:bc:22:d9:8a:22:d7:a0:fc:71:ec:91:87:20:f1:
- b8:ec:b1:e5:55:80:ac:3d:52:c8:39:0e:c2:f0:c0:05:4f:d6:
- 82:75:8c:bd:5f:d2:dc:76:9a:05:12:c9:af:72:c3:dc:25:7e:
- a4:4d:8e:17:a5:e0:87:7f:e1:9a:5a:e1:60:dc:64:23:3c:42:
- 2e:4d
-SHA1 Fingerprint=E0:AB:05:94:20:72:54:93:05:60:62:02:36:70:F7:CD:2E:FC:66:66
diff --git a/luni/src/main/files/cacerts/d18e9066.0 b/luni/src/main/files/cacerts/d18e9066.0
new file mode 100644
index 0000000..fd686a6
--- /dev/null
+++ b/luni/src/main/files/cacerts/d18e9066.0
@@ -0,0 +1,120 @@
+-----BEGIN CERTIFICATE-----
+MIIFYDCCA0igAwIBAgIQCgFCgAAAAUUjyES1AAAAAjANBgkqhkiG9w0BAQsFADBK
+MQswCQYDVQQGEwJVUzESMBAGA1UEChMJSWRlblRydXN0MScwJQYDVQQDEx5JZGVu
+VHJ1c3QgQ29tbWVyY2lhbCBSb290IENBIDEwHhcNMTQwMTE2MTgxMjIzWhcNMzQw
+MTE2MTgxMjIzWjBKMQswCQYDVQQGEwJVUzESMBAGA1UEChMJSWRlblRydXN0MScw
+JQYDVQQDEx5JZGVuVHJ1c3QgQ29tbWVyY2lhbCBSb290IENBIDEwggIiMA0GCSqG
+SIb3DQEBAQUAA4ICDwAwggIKAoICAQCnUBneP5k91DNG8W9RYYKyqU+PZ4ldhNlT
+3Qwo2dfw/66VQ3KZ+bVdfIrBQuExUHTRgQ18zZshq0PirK1ehm7zCYofWjK9ouuU
++ehcCuz/mNKvcbO0U59Oh++SvL3sTzIwiEsXXlfEU8L2ApeN2WIrvyQfYo3fw7gp
+S0l4PJNgiCL8mdo2yMKi1CxUAGc1bnO/AljwpN3lsKImesrgNqUZFvX9t++uP0D1
+bVoE/c40yiTcdCMbXTMTEl3EASX2MN0CXZ/g1Ue9tOsbobtJSdifWwLziuQkkORi
+T0/Br4sOdBeo0XKIanoBScy0RnnGF7HamB4HWfp1IYVl3ZBWzvurpWCdxJ35UrCL
+vYf5jysjCiN2O/cz4ckA82n5S6LgTrx+kzmEB/dEcH7+B1rlsazRGMzyNeVJSQjK
+Vsk9+w8YfYs7wRPCTY/JTw436R+hDmrfYi7LNQZReSzIJTj0+kuniVyc0uMNOYZK
+dHzVWYfCP04MXFL0PfdSgvHqo6z9STQaKPNBiDoT7uje/5kdX7rL6B7yuVBgwDHT
+c+XvvqDtMwt0viAgxGds8AgDelWAf0ZOlqf0Hj7h9tgJ4TNkK2PXMl6f+cB7D3hv
+l7yTmvmcEpB4eoCHFddydJxVdHixuuFucAS6T6C6aMN7/zHwcz09lCqxC0EOoP5N
+iGVreTO01wIDAQABo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB
+/zAdBgNVHQ4EFgQU7UQZwNPwBovupHu+QucmVMiONnYwDQYJKoZIhvcNAQELBQAD
+ggIBAA2ukDL2pkt8RHYZYR4nKM1eVO8lvOMIkPkp165oCOGUAFjvLi5+U1KMtlwH
+6oi6mYtQlNeCgN9hCQCTrQ0U5s7B8jeUeLBfnLOic7iPBZM4zY0+sLj7wM+x8uwt
+LRvM7Kqas6pgghstO8OEPVeKlh6cdbjTMM1gCIOQ045U8U1mwF10A0Cj7oV+wh93
+nAbowacYXVKV7cndJZ5t+qntozo00Fl72u1Q8zW/7esUTTHHYPTa8Yec4kjixsU3
++wYQ+nVZZjFHKdp2mhzpgq7vmrlR94gjmmmVYjzlVYA211QC//G5Xc7UI2/YRYRK
+W2XviQzdFKcgyxilJbQN+QHwotL0AMh0jqEqSI5l2xPE4iUXfeu+h1sXIFRRk0pT
+AwvsXcoz7WL9RccvW9xYoIA55vrX/hMUpu09lEpCdNTDd1lzzY9GvlU47/rokTLq
+l1gEIt44w8y8bckzOmoKaT+gyOpyj4xjhiO9bTyWnpXgSUyqorkqG5w2gXjtw+hG
+4iZZRHUe2XWJUc0QhJ1hYMtd+ZciTY6Y5uN/9lu7rs3KSoFrXgvzUeF0K+l+J6fZ
+mUlO+KWA2yUPHGNiiskzZ2s8EIPGrd6ozRaOjfAHN3Gf8qv8QfXBi+wAN10J5U6A
+7/qxXDgGpRtK4dw4LTzcqx+QGtVKnO7RcGzM7vRX+Bi6hG6H
+-----END CERTIFICATE-----
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number:
+ 0a:01:42:80:00:00:01:45:23:c8:44:b5:00:00:00:02
+ Signature Algorithm: sha256WithRSAEncryption
+ Issuer: C=US, O=IdenTrust, CN=IdenTrust Commercial Root CA 1
+ Validity
+ Not Before: Jan 16 18:12:23 2014 GMT
+ Not After : Jan 16 18:12:23 2034 GMT
+ Subject: C=US, O=IdenTrust, CN=IdenTrust Commercial Root CA 1
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ Public-Key: (4096 bit)
+ Modulus:
+ 00:a7:50:19:de:3f:99:3d:d4:33:46:f1:6f:51:61:
+ 82:b2:a9:4f:8f:67:89:5d:84:d9:53:dd:0c:28:d9:
+ d7:f0:ff:ae:95:43:72:99:f9:b5:5d:7c:8a:c1:42:
+ e1:31:50:74:d1:81:0d:7c:cd:9b:21:ab:43:e2:ac:
+ ad:5e:86:6e:f3:09:8a:1f:5a:32:bd:a2:eb:94:f9:
+ e8:5c:0a:ec:ff:98:d2:af:71:b3:b4:53:9f:4e:87:
+ ef:92:bc:bd:ec:4f:32:30:88:4b:17:5e:57:c4:53:
+ c2:f6:02:97:8d:d9:62:2b:bf:24:1f:62:8d:df:c3:
+ b8:29:4b:49:78:3c:93:60:88:22:fc:99:da:36:c8:
+ c2:a2:d4:2c:54:00:67:35:6e:73:bf:02:58:f0:a4:
+ dd:e5:b0:a2:26:7a:ca:e0:36:a5:19:16:f5:fd:b7:
+ ef:ae:3f:40:f5:6d:5a:04:fd:ce:34:ca:24:dc:74:
+ 23:1b:5d:33:13:12:5d:c4:01:25:f6:30:dd:02:5d:
+ 9f:e0:d5:47:bd:b4:eb:1b:a1:bb:49:49:d8:9f:5b:
+ 02:f3:8a:e4:24:90:e4:62:4f:4f:c1:af:8b:0e:74:
+ 17:a8:d1:72:88:6a:7a:01:49:cc:b4:46:79:c6:17:
+ b1:da:98:1e:07:59:fa:75:21:85:65:dd:90:56:ce:
+ fb:ab:a5:60:9d:c4:9d:f9:52:b0:8b:bd:87:f9:8f:
+ 2b:23:0a:23:76:3b:f7:33:e1:c9:00:f3:69:f9:4b:
+ a2:e0:4e:bc:7e:93:39:84:07:f7:44:70:7e:fe:07:
+ 5a:e5:b1:ac:d1:18:cc:f2:35:e5:49:49:08:ca:56:
+ c9:3d:fb:0f:18:7d:8b:3b:c1:13:c2:4d:8f:c9:4f:
+ 0e:37:e9:1f:a1:0e:6a:df:62:2e:cb:35:06:51:79:
+ 2c:c8:25:38:f4:fa:4b:a7:89:5c:9c:d2:e3:0d:39:
+ 86:4a:74:7c:d5:59:87:c2:3f:4e:0c:5c:52:f4:3d:
+ f7:52:82:f1:ea:a3:ac:fd:49:34:1a:28:f3:41:88:
+ 3a:13:ee:e8:de:ff:99:1d:5f:ba:cb:e8:1e:f2:b9:
+ 50:60:c0:31:d3:73:e5:ef:be:a0:ed:33:0b:74:be:
+ 20:20:c4:67:6c:f0:08:03:7a:55:80:7f:46:4e:96:
+ a7:f4:1e:3e:e1:f6:d8:09:e1:33:64:2b:63:d7:32:
+ 5e:9f:f9:c0:7b:0f:78:6f:97:bc:93:9a:f9:9c:12:
+ 90:78:7a:80:87:15:d7:72:74:9c:55:74:78:b1:ba:
+ e1:6e:70:04:ba:4f:a0:ba:68:c3:7b:ff:31:f0:73:
+ 3d:3d:94:2a:b1:0b:41:0e:a0:fe:4d:88:65:6b:79:
+ 33:b4:d7
+ Exponent: 65537 (0x10001)
+ X509v3 extensions:
+ X509v3 Key Usage: critical
+ Certificate Sign, CRL Sign
+ X509v3 Basic Constraints: critical
+ CA:TRUE
+ X509v3 Subject Key Identifier:
+ ED:44:19:C0:D3:F0:06:8B:EE:A4:7B:BE:42:E7:26:54:C8:8E:36:76
+ Signature Algorithm: sha256WithRSAEncryption
+ 0d:ae:90:32:f6:a6:4b:7c:44:76:19:61:1e:27:28:cd:5e:54:
+ ef:25:bc:e3:08:90:f9:29:d7:ae:68:08:e1:94:00:58:ef:2e:
+ 2e:7e:53:52:8c:b6:5c:07:ea:88:ba:99:8b:50:94:d7:82:80:
+ df:61:09:00:93:ad:0d:14:e6:ce:c1:f2:37:94:78:b0:5f:9c:
+ b3:a2:73:b8:8f:05:93:38:cd:8d:3e:b0:b8:fb:c0:cf:b1:f2:
+ ec:2d:2d:1b:cc:ec:aa:9a:b3:aa:60:82:1b:2d:3b:c3:84:3d:
+ 57:8a:96:1e:9c:75:b8:d3:30:cd:60:08:83:90:d3:8e:54:f1:
+ 4d:66:c0:5d:74:03:40:a3:ee:85:7e:c2:1f:77:9c:06:e8:c1:
+ a7:18:5d:52:95:ed:c9:dd:25:9e:6d:fa:a9:ed:a3:3a:34:d0:
+ 59:7b:da:ed:50:f3:35:bf:ed:eb:14:4d:31:c7:60:f4:da:f1:
+ 87:9c:e2:48:e2:c6:c5:37:fb:06:10:fa:75:59:66:31:47:29:
+ da:76:9a:1c:e9:82:ae:ef:9a:b9:51:f7:88:23:9a:69:95:62:
+ 3c:e5:55:80:36:d7:54:02:ff:f1:b9:5d:ce:d4:23:6f:d8:45:
+ 84:4a:5b:65:ef:89:0c:dd:14:a7:20:cb:18:a5:25:b4:0d:f9:
+ 01:f0:a2:d2:f4:00:c8:74:8e:a1:2a:48:8e:65:db:13:c4:e2:
+ 25:17:7d:eb:be:87:5b:17:20:54:51:93:4a:53:03:0b:ec:5d:
+ ca:33:ed:62:fd:45:c7:2f:5b:dc:58:a0:80:39:e6:fa:d7:fe:
+ 13:14:a6:ed:3d:94:4a:42:74:d4:c3:77:59:73:cd:8f:46:be:
+ 55:38:ef:fa:e8:91:32:ea:97:58:04:22:de:38:c3:cc:bc:6d:
+ c9:33:3a:6a:0a:69:3f:a0:c8:ea:72:8f:8c:63:86:23:bd:6d:
+ 3c:96:9e:95:e0:49:4c:aa:a2:b9:2a:1b:9c:36:81:78:ed:c3:
+ e8:46:e2:26:59:44:75:1e:d9:75:89:51:cd:10:84:9d:61:60:
+ cb:5d:f9:97:22:4d:8e:98:e6:e3:7f:f6:5b:bb:ae:cd:ca:4a:
+ 81:6b:5e:0b:f3:51:e1:74:2b:e9:7e:27:a7:d9:99:49:4e:f8:
+ a5:80:db:25:0f:1c:63:62:8a:c9:33:67:6b:3c:10:83:c6:ad:
+ de:a8:cd:16:8e:8d:f0:07:37:71:9f:f2:ab:fc:41:f5:c1:8b:
+ ec:00:37:5d:09:e5:4e:80:ef:fa:b1:5c:38:06:a5:1b:4a:e1:
+ dc:38:2d:3c:dc:ab:1f:90:1a:d5:4a:9c:ee:d1:70:6c:cc:ee:
+ f4:57:f8:18:ba:84:6e:87
+SHA1 Fingerprint=DF:71:7E:AA:4A:D9:4E:C9:55:84:99:60:2D:48:DE:5F:BC:F0:3A:25
diff --git a/luni/src/main/files/cacerts/d6e6eab9.0 b/luni/src/main/files/cacerts/d6e6eab9.0
new file mode 100644
index 0000000..aff6bdf
--- /dev/null
+++ b/luni/src/main/files/cacerts/d6e6eab9.0
@@ -0,0 +1,123 @@
+-----BEGIN CERTIFICATE-----
+MIIFkjCCA3qgAwIBAgIBATANBgkqhkiG9w0BAQsFADBaMQswCQYDVQQGEwJGUjET
+MBEGA1UEChMKQ2VydGlub21pczEXMBUGA1UECxMOMDAwMiA0MzM5OTg5MDMxHTAb
+BgNVBAMTFENlcnRpbm9taXMgLSBSb290IENBMB4XDTEzMTAyMTA5MTcxOFoXDTMz
+MTAyMTA5MTcxOFowWjELMAkGA1UEBhMCRlIxEzARBgNVBAoTCkNlcnRpbm9taXMx
+FzAVBgNVBAsTDjAwMDIgNDMzOTk4OTAzMR0wGwYDVQQDExRDZXJ0aW5vbWlzIC0g
+Um9vdCBDQTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBANTMCQosP5L2
+fxSeC5yaah1AMGT9qt8OHgZbn1CF6s2Nq0Nn3rD6foCWnoR4kkjW4znuzuRZWJfl
+LieY6pOod5tK8O90gC3rMB+12ceAnGInkYjwSond3IjmFPnVAy//ldu9n+ws+hQV
+WZUKxkd8aRi5pwP5ynapz8dvtF4F/u7BUrJ1Mofs7SlmO/NKFoL21prbcpjp3vDF
+TKWrteoB4owuZH9kb/2jJZOLyKIOSY008B/sWEUuNKqEUL3nskoTuLAPrjhdsKkb
+5nPJWqHZZkCqqU2mNAKthH6yI8H7KsZn9DS2sJVqM09xRLWtwHkziOC/7aOgFLSc
+CbAK42C++PhmiM1b8XcF4LVzbsF9Ri6OSyemzTUK/eVNfaoqoynHWmgE6OXWk6Ri
+wsXm9E/G+Z8ajYJJGYrKWUM66A0ywfRMEwNvbqY/kXPLynNvEiCL7sCCeN5LLsJJ
+wx3tFvYk9CcbXFcx3FXuqB5vbKziRcxXV4p1VxngtViZSTYxPDMBbRZKzbgqg4SG
+m/lg0h9tkQPTYKbVPZrdd5A9NaSfD171UkRpucC63M9933zZxKyGIjK8e2uR73r4
+F2iw4lNVYC2vPsKD2NkJK/DAZNuHi5HMkesE/Xa0lZrmFAYb1TQdvtj/dBxThZng
+WVJKYe2InmtJiUZ+IFrZ50rlau7SZRFDAgMBAAGjYzBhMA4GA1UdDwEB/wQEAwIB
+BjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBTvkUz1pcMw6C8I6tNxIqSSaHh0
+2TAfBgNVHSMEGDAWgBTvkUz1pcMw6C8I6tNxIqSSaHh02TANBgkqhkiG9w0BAQsF
+AAOCAgEAfj1U2iJdGlg+O1QnurrMyOMaauo++RLrVl89UM7g6kgmJs95Vn6RHJk/
+0KGRHCwPT5iVWVO90CLYiF2cN/z7ZMF4jIuaYAnq1fohX9B0ZedQxb8uuQsLrbWw
+F6YSjNRieOpWauwK0kDDPAUwPk2Ut59KA9N9J0u2/kTO+hkzGm2kQtHdzMjI1xZS
+g081lLMSVX3l4kLr5JyTCcBMWwerx20RoFAXlCOotQqSD7J6wWAsOMwaplv/8gzj
+qh8c3LigkyfeY+N/IZ865Z764BNqdeuWXGKRlI5nU7aJ+BIJy29SWwNyhlCVCNSN
+h4YVH5Uk2KRvms6knZtt0rJ2BobGVgjF6wnaNsIbW0G+YSrjcOa4pvi2WsS9Iff/
+ql+hbHY5ZtbqTFXhADObE5hjyW/QASAJN1LnDE8+zbz1X5YnpyACleAu6AdBBR8V
+btaw5BngDwKTACdyxYvRVB9dSsNAl35VpnzBMwQUAR1JIGkLGZOdblgi90AMRgwj
+Y/M50n92Uaf0yKHxDHYiI0ZSKS3io0EHVmmY0gUJvGnHWmHNj4FgFU2A3ZDifcRQ
+8ow7bkrHxuaAKzyBvBGAFhAn1/DNP3nMcyrDflOR1m749fPH0FFNjkulW+YZFzvW
+gQncItzujrnEj1PhZ7szuIgVRs/taTX/dQ1G885x4cVrhkIGuUE=
+-----END CERTIFICATE-----
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number: 1 (0x1)
+ Signature Algorithm: sha256WithRSAEncryption
+ Issuer: C=FR, O=Certinomis, OU=0002 433998903, CN=Certinomis - Root CA
+ Validity
+ Not Before: Oct 21 09:17:18 2013 GMT
+ Not After : Oct 21 09:17:18 2033 GMT
+ Subject: C=FR, O=Certinomis, OU=0002 433998903, CN=Certinomis - Root CA
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ Public-Key: (4096 bit)
+ Modulus:
+ 00:d4:cc:09:0a:2c:3f:92:f6:7f:14:9e:0b:9c:9a:
+ 6a:1d:40:30:64:fd:aa:df:0e:1e:06:5b:9f:50:85:
+ ea:cd:8d:ab:43:67:de:b0:fa:7e:80:96:9e:84:78:
+ 92:48:d6:e3:39:ee:ce:e4:59:58:97:e5:2e:27:98:
+ ea:93:a8:77:9b:4a:f0:ef:74:80:2d:eb:30:1f:b5:
+ d9:c7:80:9c:62:27:91:88:f0:4a:89:dd:dc:88:e6:
+ 14:f9:d5:03:2f:ff:95:db:bd:9f:ec:2c:fa:14:15:
+ 59:95:0a:c6:47:7c:69:18:b9:a7:03:f9:ca:76:a9:
+ cf:c7:6f:b4:5e:05:fe:ee:c1:52:b2:75:32:87:ec:
+ ed:29:66:3b:f3:4a:16:82:f6:d6:9a:db:72:98:e9:
+ de:f0:c5:4c:a5:ab:b5:ea:01:e2:8c:2e:64:7f:64:
+ 6f:fd:a3:25:93:8b:c8:a2:0e:49:8d:34:f0:1f:ec:
+ 58:45:2e:34:aa:84:50:bd:e7:b2:4a:13:b8:b0:0f:
+ ae:38:5d:b0:a9:1b:e6:73:c9:5a:a1:d9:66:40:aa:
+ a9:4d:a6:34:02:ad:84:7e:b2:23:c1:fb:2a:c6:67:
+ f4:34:b6:b0:95:6a:33:4f:71:44:b5:ad:c0:79:33:
+ 88:e0:bf:ed:a3:a0:14:b4:9c:09:b0:0a:e3:60:be:
+ f8:f8:66:88:cd:5b:f1:77:05:e0:b5:73:6e:c1:7d:
+ 46:2e:8e:4b:27:a6:cd:35:0a:fd:e5:4d:7d:aa:2a:
+ a3:29:c7:5a:68:04:e8:e5:d6:93:a4:62:c2:c5:e6:
+ f4:4f:c6:f9:9f:1a:8d:82:49:19:8a:ca:59:43:3a:
+ e8:0d:32:c1:f4:4c:13:03:6f:6e:a6:3f:91:73:cb:
+ ca:73:6f:12:20:8b:ee:c0:82:78:de:4b:2e:c2:49:
+ c3:1d:ed:16:f6:24:f4:27:1b:5c:57:31:dc:55:ee:
+ a8:1e:6f:6c:ac:e2:45:cc:57:57:8a:75:57:19:e0:
+ b5:58:99:49:36:31:3c:33:01:6d:16:4a:cd:b8:2a:
+ 83:84:86:9b:f9:60:d2:1f:6d:91:03:d3:60:a6:d5:
+ 3d:9a:dd:77:90:3d:35:a4:9f:0f:5e:f5:52:44:69:
+ b9:c0:ba:dc:cf:7d:df:7c:d9:c4:ac:86:22:32:bc:
+ 7b:6b:91:ef:7a:f8:17:68:b0:e2:53:55:60:2d:af:
+ 3e:c2:83:d8:d9:09:2b:f0:c0:64:db:87:8b:91:cc:
+ 91:eb:04:fd:76:b4:95:9a:e6:14:06:1b:d5:34:1d:
+ be:d8:ff:74:1c:53:85:99:e0:59:52:4a:61:ed:88:
+ 9e:6b:49:89:46:7e:20:5a:d9:e7:4a:e5:6a:ee:d2:
+ 65:11:43
+ Exponent: 65537 (0x10001)
+ X509v3 extensions:
+ X509v3 Key Usage: critical
+ Certificate Sign, CRL Sign
+ X509v3 Basic Constraints: critical
+ CA:TRUE
+ X509v3 Subject Key Identifier:
+ EF:91:4C:F5:A5:C3:30:E8:2F:08:EA:D3:71:22:A4:92:68:78:74:D9
+ X509v3 Authority Key Identifier:
+ keyid:EF:91:4C:F5:A5:C3:30:E8:2F:08:EA:D3:71:22:A4:92:68:78:74:D9
+
+ Signature Algorithm: sha256WithRSAEncryption
+ 7e:3d:54:da:22:5d:1a:58:3e:3b:54:27:ba:ba:cc:c8:e3:1a:
+ 6a:ea:3e:f9:12:eb:56:5f:3d:50:ce:e0:ea:48:26:26:cf:79:
+ 56:7e:91:1c:99:3f:d0:a1:91:1c:2c:0f:4f:98:95:59:53:bd:
+ d0:22:d8:88:5d:9c:37:fc:fb:64:c1:78:8c:8b:9a:60:09:ea:
+ d5:fa:21:5f:d0:74:65:e7:50:c5:bf:2e:b9:0b:0b:ad:b5:b0:
+ 17:a6:12:8c:d4:62:78:ea:56:6a:ec:0a:d2:40:c3:3c:05:30:
+ 3e:4d:94:b7:9f:4a:03:d3:7d:27:4b:b6:fe:44:ce:fa:19:33:
+ 1a:6d:a4:42:d1:dd:cc:c8:c8:d7:16:52:83:4f:35:94:b3:12:
+ 55:7d:e5:e2:42:eb:e4:9c:93:09:c0:4c:5b:07:ab:c7:6d:11:
+ a0:50:17:94:23:a8:b5:0a:92:0f:b2:7a:c1:60:2c:38:cc:1a:
+ a6:5b:ff:f2:0c:e3:aa:1f:1c:dc:b8:a0:93:27:de:63:e3:7f:
+ 21:9f:3a:e5:9e:fa:e0:13:6a:75:eb:96:5c:62:91:94:8e:67:
+ 53:b6:89:f8:12:09:cb:6f:52:5b:03:72:86:50:95:08:d4:8d:
+ 87:86:15:1f:95:24:d8:a4:6f:9a:ce:a4:9d:9b:6d:d2:b2:76:
+ 06:86:c6:56:08:c5:eb:09:da:36:c2:1b:5b:41:be:61:2a:e3:
+ 70:e6:b8:a6:f8:b6:5a:c4:bd:21:f7:ff:aa:5f:a1:6c:76:39:
+ 66:d6:ea:4c:55:e1:00:33:9b:13:98:63:c9:6f:d0:01:20:09:
+ 37:52:e7:0c:4f:3e:cd:bc:f5:5f:96:27:a7:20:02:95:e0:2e:
+ e8:07:41:05:1f:15:6e:d6:b0:e4:19:e0:0f:02:93:00:27:72:
+ c5:8b:d1:54:1f:5d:4a:c3:40:97:7e:55:a6:7c:c1:33:04:14:
+ 01:1d:49:20:69:0b:19:93:9d:6e:58:22:f7:40:0c:46:0c:23:
+ 63:f3:39:d2:7f:76:51:a7:f4:c8:a1:f1:0c:76:22:23:46:52:
+ 29:2d:e2:a3:41:07:56:69:98:d2:05:09:bc:69:c7:5a:61:cd:
+ 8f:81:60:15:4d:80:dd:90:e2:7d:c4:50:f2:8c:3b:6e:4a:c7:
+ c6:e6:80:2b:3c:81:bc:11:80:16:10:27:d7:f0:cd:3f:79:cc:
+ 73:2a:c3:7e:53:91:d6:6e:f8:f5:f3:c7:d0:51:4d:8e:4b:a5:
+ 5b:e6:19:17:3b:d6:81:09:dc:22:dc:ee:8e:b9:c4:8f:53:e1:
+ 67:bb:33:b8:88:15:46:cf:ed:69:35:ff:75:0d:46:f3:ce:71:
+ e1:c5:6b:86:42:06:b9:41
+SHA1 Fingerprint=9D:70:BB:01:A5:A4:A0:18:11:2E:F7:1C:01:B9:32:C5:34:E7:88:A8
diff --git a/luni/src/main/files/cacerts/ddc328ff.0 b/luni/src/main/files/cacerts/ddc328ff.0
deleted file mode 100644
index bcc8a9a..0000000
--- a/luni/src/main/files/cacerts/ddc328ff.0
+++ /dev/null
@@ -1,57 +0,0 @@
------BEGIN CERTIFICATE-----
-MIIDIjCCAougAwIBAgIQNKT/9jCvTKU8MxdCoZRmdTANBgkqhkiG9w0BAQUFADCB
-xDELMAkGA1UEBhMCWkExFTATBgNVBAgTDFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJ
-Q2FwZSBUb3duMR0wGwYDVQQKExRUaGF3dGUgQ29uc3VsdGluZyBjYzEoMCYGA1UE
-CxMfQ2VydGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjEZMBcGA1UEAxMQVGhh
-d3RlIFNlcnZlciBDQTEmMCQGCSqGSIb3DQEJARYXc2VydmVyLWNlcnRzQHRoYXd0
-ZS5jb20wHhcNOTYwODAxMDAwMDAwWhcNMjEwMTAxMjM1OTU5WjCBxDELMAkGA1UE
-BhMCWkExFTATBgNVBAgTDFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJQ2FwZSBUb3du
-MR0wGwYDVQQKExRUaGF3dGUgQ29uc3VsdGluZyBjYzEoMCYGA1UECxMfQ2VydGlm
-aWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjEZMBcGA1UEAxMQVGhhd3RlIFNlcnZl
-ciBDQTEmMCQGCSqGSIb3DQEJARYXc2VydmVyLWNlcnRzQHRoYXd0ZS5jb20wgZ8w
-DQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBANOkUG7I/1Zr5s9dtuoMaHVHoqrC2oQl
-/Kj0R1HahbUgdJSGHg91yekIYfUGbTBuFRkC6VLAYttNmZ7iagxEOM3+vuNkCXDF
-/rFrKbYvScg71CcEJRCXL+eQbcAoQpnXTEPew/UhbVSfXcNY4cDk2VuwuNy0e982
-OsK1ZiIS1ocNAgMBAAGjEzARMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEF
-BQADgYEAvkBpQW/G28GnvwfAReTQtUMeTJUzNelewj4o9qgNUNX/4gwP/FACjq6R
-ua00io2fJ3GqGcxL6ATK1BdrEhrWxl/WzV7/iXa/2EjYWb0IiokdV81FHlK6EpqE
-+hiJX+j5MDVqAWC5mYCDhQpu2vTJj15zLTFKY6B08h+LItIpPus=
------END CERTIFICATE-----
-Certificate:
- Data:
- Version: 3 (0x2)
- Serial Number:
- 34:a4:ff:f6:30:af:4c:a5:3c:33:17:42:a1:94:66:75
- Signature Algorithm: sha1WithRSAEncryption
- Issuer: C=ZA, ST=Western Cape, L=Cape Town, O=Thawte Consulting cc, OU=Certification Services Division, CN=Thawte Server CA/emailAddress=server-certs@thawte.com
- Validity
- Not Before: Aug 1 00:00:00 1996 GMT
- Not After : Jan 1 23:59:59 2021 GMT
- Subject: C=ZA, ST=Western Cape, L=Cape Town, O=Thawte Consulting cc, OU=Certification Services Division, CN=Thawte Server CA/emailAddress=server-certs@thawte.com
- Subject Public Key Info:
- Public Key Algorithm: rsaEncryption
- Public-Key: (1024 bit)
- Modulus:
- 00:d3:a4:50:6e:c8:ff:56:6b:e6:cf:5d:b6:ea:0c:
- 68:75:47:a2:aa:c2:da:84:25:fc:a8:f4:47:51:da:
- 85:b5:20:74:94:86:1e:0f:75:c9:e9:08:61:f5:06:
- 6d:30:6e:15:19:02:e9:52:c0:62:db:4d:99:9e:e2:
- 6a:0c:44:38:cd:fe:be:e3:64:09:70:c5:fe:b1:6b:
- 29:b6:2f:49:c8:3b:d4:27:04:25:10:97:2f:e7:90:
- 6d:c0:28:42:99:d7:4c:43:de:c3:f5:21:6d:54:9f:
- 5d:c3:58:e1:c0:e4:d9:5b:b0:b8:dc:b4:7b:df:36:
- 3a:c2:b5:66:22:12:d6:87:0d
- Exponent: 65537 (0x10001)
- X509v3 extensions:
- X509v3 Basic Constraints: critical
- CA:TRUE
- Signature Algorithm: sha1WithRSAEncryption
- be:40:69:41:6f:c6:db:c1:a7:bf:07:c0:45:e4:d0:b5:43:1e:
- 4c:95:33:35:e9:5e:c2:3e:28:f6:a8:0d:50:d5:ff:e2:0c:0f:
- fc:50:02:8e:ae:91:b9:ad:34:8a:8d:9f:27:71:aa:19:cc:4b:
- e8:04:ca:d4:17:6b:12:1a:d6:c6:5f:d6:cd:5e:ff:89:76:bf:
- d8:48:d8:59:bd:08:8a:89:1d:57:cd:45:1e:52:ba:12:9a:84:
- fa:18:89:5f:e8:f9:30:35:6a:01:60:b9:99:80:83:85:0a:6e:
- da:f4:c9:8f:5e:73:2d:31:4a:63:a0:74:f2:1f:8b:22:d2:29:
- 3e:eb
-SHA1 Fingerprint=9F:AD:91:A6:CE:6A:C6:C5:00:47:C4:4E:C9:D4:A5:0D:92:D8:49:79
diff --git a/luni/src/main/files/cacerts/e7b8d656.0 b/luni/src/main/files/cacerts/e7b8d656.0
deleted file mode 100644
index a019756..0000000
--- a/luni/src/main/files/cacerts/e7b8d656.0
+++ /dev/null
@@ -1,60 +0,0 @@
------BEGIN CERTIFICATE-----
-MIICgjCCAeugAwIBAgIBBDANBgkqhkiG9w0BAQQFADBTMQswCQYDVQQGEwJVUzEc
-MBoGA1UEChMTRXF1aWZheCBTZWN1cmUgSW5jLjEmMCQGA1UEAxMdRXF1aWZheCBT
-ZWN1cmUgZUJ1c2luZXNzIENBLTEwHhcNOTkwNjIxMDQwMDAwWhcNMjAwNjIxMDQw
-MDAwWjBTMQswCQYDVQQGEwJVUzEcMBoGA1UEChMTRXF1aWZheCBTZWN1cmUgSW5j
-LjEmMCQGA1UEAxMdRXF1aWZheCBTZWN1cmUgZUJ1c2luZXNzIENBLTEwgZ8wDQYJ
-KoZIhvcNAQEBBQADgY0AMIGJAoGBAM4vGbwXt3fek6lfWg0XTzQaDJj0ItlZ1MRo
-RvC0NcWFAyDGr0WlIVFFQesWWDYyb+JQYmT5/VGcqiTZ9J2DKocKIdMSODRsjQBu
-WqDZQu4aIZX5UkxVWsUPOE9G+m34LjXWHXzr4vCwdYDIqROsvojvOm6rXyo4YgKw
-Env+j6YDAgMBAAGjZjBkMBEGCWCGSAGG+EIBAQQEAwIABzAPBgNVHRMBAf8EBTAD
-AQH/MB8GA1UdIwQYMBaAFEp4MlIR21kWNl7fwRQ2QGpHfEyhMB0GA1UdDgQWBBRK
-eDJSEdtZFjZe38EUNkBqR3xMoTANBgkqhkiG9w0BAQQFAAOBgQB1W6ibAxHm6VZM
-zfmpTMANmvPMZWnmJXbMWbfWVMMdzZmsGd20hdXgPfxiIKeES1hl8eL5lSE/9dR+
-WB5Hh1Q+WKG1tfgq73HnvMP2sUlG4tega+VWeponmHxGYhTnyfxuAxJ5gDgdSIKN
-/Bf+KpYrtWKmpj29f5JZzVoqgrI3eQ==
------END CERTIFICATE-----
-Certificate:
- Data:
- Version: 3 (0x2)
- Serial Number: 4 (0x4)
- Signature Algorithm: md5WithRSAEncryption
- Issuer: C=US, O=Equifax Secure Inc., CN=Equifax Secure eBusiness CA-1
- Validity
- Not Before: Jun 21 04:00:00 1999 GMT
- Not After : Jun 21 04:00:00 2020 GMT
- Subject: C=US, O=Equifax Secure Inc., CN=Equifax Secure eBusiness CA-1
- Subject Public Key Info:
- Public Key Algorithm: rsaEncryption
- Public-Key: (1024 bit)
- Modulus:
- 00:ce:2f:19:bc:17:b7:77:de:93:a9:5f:5a:0d:17:
- 4f:34:1a:0c:98:f4:22:d9:59:d4:c4:68:46:f0:b4:
- 35:c5:85:03:20:c6:af:45:a5:21:51:45:41:eb:16:
- 58:36:32:6f:e2:50:62:64:f9:fd:51:9c:aa:24:d9:
- f4:9d:83:2a:87:0a:21:d3:12:38:34:6c:8d:00:6e:
- 5a:a0:d9:42:ee:1a:21:95:f9:52:4c:55:5a:c5:0f:
- 38:4f:46:fa:6d:f8:2e:35:d6:1d:7c:eb:e2:f0:b0:
- 75:80:c8:a9:13:ac:be:88:ef:3a:6e:ab:5f:2a:38:
- 62:02:b0:12:7b:fe:8f:a6:03
- Exponent: 65537 (0x10001)
- X509v3 extensions:
- Netscape Cert Type:
- SSL CA, S/MIME CA, Object Signing CA
- X509v3 Basic Constraints: critical
- CA:TRUE
- X509v3 Authority Key Identifier:
- keyid:4A:78:32:52:11:DB:59:16:36:5E:DF:C1:14:36:40:6A:47:7C:4C:A1
-
- X509v3 Subject Key Identifier:
- 4A:78:32:52:11:DB:59:16:36:5E:DF:C1:14:36:40:6A:47:7C:4C:A1
- Signature Algorithm: md5WithRSAEncryption
- 75:5b:a8:9b:03:11:e6:e9:56:4c:cd:f9:a9:4c:c0:0d:9a:f3:
- cc:65:69:e6:25:76:cc:59:b7:d6:54:c3:1d:cd:99:ac:19:dd:
- b4:85:d5:e0:3d:fc:62:20:a7:84:4b:58:65:f1:e2:f9:95:21:
- 3f:f5:d4:7e:58:1e:47:87:54:3e:58:a1:b5:b5:f8:2a:ef:71:
- e7:bc:c3:f6:b1:49:46:e2:d7:a0:6b:e5:56:7a:9a:27:98:7c:
- 46:62:14:e7:c9:fc:6e:03:12:79:80:38:1d:48:82:8d:fc:17:
- fe:2a:96:2b:b5:62:a6:a6:3d:bd:7f:92:59:cd:5a:2a:82:b2:
- 37:79
-SHA1 Fingerprint=DA:40:18:8B:91:89:A3:ED:EE:AE:DA:97:FE:2F:9D:F5:B7:D1:8A:41
diff --git a/luni/src/main/files/cacerts/eb375c3e.0 b/luni/src/main/files/cacerts/eb375c3e.0
deleted file mode 100644
index 739b045..0000000
--- a/luni/src/main/files/cacerts/eb375c3e.0
+++ /dev/null
@@ -1,77 +0,0 @@
------BEGIN CERTIFICATE-----
-MIIDUzCCAjugAwIBAgIBAjANBgkqhkiG9w0BAQUFADBLMQswCQYDVQQGEwJOTzEd
-MBsGA1UECgwUQnV5cGFzcyBBUy05ODMxNjMzMjcxHTAbBgNVBAMMFEJ1eXBhc3Mg
-Q2xhc3MgMyBDQSAxMB4XDTA1MDUwOTE0MTMwM1oXDTE1MDUwOTE0MTMwM1owSzEL
-MAkGA1UEBhMCTk8xHTAbBgNVBAoMFEJ1eXBhc3MgQVMtOTgzMTYzMzI3MR0wGwYD
-VQQDDBRCdXlwYXNzIENsYXNzIDMgQ0EgMTCCASIwDQYJKoZIhvcNAQEBBQADggEP
-ADCCAQoCggEBAKSO13TZKWTeXx+HgJHqTjnmGcZEC4DVC69TB4sSveZn8AKxifZg
-isRbsELRwCGoy+Gb72RRtqfPFfV0gGgEkKBYouZ0plNTVUhjP5JW3SROjvi6K//z
-NIqeKNc0n6wv1g/xpC+9UrJJhW05NfBEMJNGJPO251P7vGGvqaMU+8IXF4Rs4HyI
-+MkcVyzwPX6UvCWThOiaAJpFBUJXgPROztmuOfbIUxAMZTpHe2DC1vqRycZxbL2R
-hzyRhkmr8w+gbCZ2Xhysm3HljbybIR6c1jh+JIAVMYKWsUnTYjdbiAwKYjT+p0h+
-mbEwi5A3lRyoH6UsjfRVyNvdWQrCrXig9IsCAwEAAaNCMEAwDwYDVR0TAQH/BAUw
-AwEB/zAdBgNVHQ4EFgQUOBTmyPCppAP0Tj4io1vy1uCtQHQwDgYDVR0PAQH/BAQD
-AgEGMA0GCSqGSIb3DQEBBQUAA4IBAQABZ6OMySU9E2NdFm/soT4JXJEVKirZgCFP
-Bdy7pYmrEzMqnji3jG8CcmPHc3ceCQa6Oyh7pEfJYWsICCD8igWKH7y6xsL+z27s
-EzNxZy5p+qksP2bAEllNC1QCkoS72xLvg3BweMhT+t/Gxv/ciC8HwEmdMldg0/L2
-mSlf56oBzKwzqBwKu5HEA6BvtjT5htOzdlSY9EqBs1OdTUDs5XcTRa9bqh/YL0yC
-e/4qxFi7T/ye/QNlGioOw6UgFpRreaaiErS7GqQjel/wroQk5PMr+4okoyeYZdow
-dXb8GZHo2+ubPzK/QJcHJrrM85SFSnonk8+QQtS4Wxam58tAA915
------END CERTIFICATE-----
-Certificate:
- Data:
- Version: 3 (0x2)
- Serial Number: 2 (0x2)
- Signature Algorithm: sha1WithRSAEncryption
- Issuer: C=NO, O=Buypass AS-983163327, CN=Buypass Class 3 CA 1
- Validity
- Not Before: May 9 14:13:03 2005 GMT
- Not After : May 9 14:13:03 2015 GMT
- Subject: C=NO, O=Buypass AS-983163327, CN=Buypass Class 3 CA 1
- Subject Public Key Info:
- Public Key Algorithm: rsaEncryption
- Public-Key: (2048 bit)
- Modulus:
- 00:a4:8e:d7:74:d9:29:64:de:5f:1f:87:80:91:ea:
- 4e:39:e6:19:c6:44:0b:80:d5:0b:af:53:07:8b:12:
- bd:e6:67:f0:02:b1:89:f6:60:8a:c4:5b:b0:42:d1:
- c0:21:a8:cb:e1:9b:ef:64:51:b6:a7:cf:15:f5:74:
- 80:68:04:90:a0:58:a2:e6:74:a6:53:53:55:48:63:
- 3f:92:56:dd:24:4e:8e:f8:ba:2b:ff:f3:34:8a:9e:
- 28:d7:34:9f:ac:2f:d6:0f:f1:a4:2f:bd:52:b2:49:
- 85:6d:39:35:f0:44:30:93:46:24:f3:b6:e7:53:fb:
- bc:61:af:a9:a3:14:fb:c2:17:17:84:6c:e0:7c:88:
- f8:c9:1c:57:2c:f0:3d:7e:94:bc:25:93:84:e8:9a:
- 00:9a:45:05:42:57:80:f4:4e:ce:d9:ae:39:f6:c8:
- 53:10:0c:65:3a:47:7b:60:c2:d6:fa:91:c9:c6:71:
- 6c:bd:91:87:3c:91:86:49:ab:f3:0f:a0:6c:26:76:
- 5e:1c:ac:9b:71:e5:8d:bc:9b:21:1e:9c:d6:38:7e:
- 24:80:15:31:82:96:b1:49:d3:62:37:5b:88:0c:0a:
- 62:34:fe:a7:48:7e:99:b1:30:8b:90:37:95:1c:a8:
- 1f:a5:2c:8d:f4:55:c8:db:dd:59:0a:c2:ad:78:a0:
- f4:8b
- Exponent: 65537 (0x10001)
- X509v3 extensions:
- X509v3 Basic Constraints: critical
- CA:TRUE
- X509v3 Subject Key Identifier:
- 38:14:E6:C8:F0:A9:A4:03:F4:4E:3E:22:A3:5B:F2:D6:E0:AD:40:74
- X509v3 Key Usage: critical
- Certificate Sign, CRL Sign
- Signature Algorithm: sha1WithRSAEncryption
- 01:67:a3:8c:c9:25:3d:13:63:5d:16:6f:ec:a1:3e:09:5c:91:
- 15:2a:2a:d9:80:21:4f:05:dc:bb:a5:89:ab:13:33:2a:9e:38:
- b7:8c:6f:02:72:63:c7:73:77:1e:09:06:ba:3b:28:7b:a4:47:
- c9:61:6b:08:08:20:fc:8a:05:8a:1f:bc:ba:c6:c2:fe:cf:6e:
- ec:13:33:71:67:2e:69:fa:a9:2c:3f:66:c0:12:59:4d:0b:54:
- 02:92:84:bb:db:12:ef:83:70:70:78:c8:53:fa:df:c6:c6:ff:
- dc:88:2f:07:c0:49:9d:32:57:60:d3:f2:f6:99:29:5f:e7:aa:
- 01:cc:ac:33:a8:1c:0a:bb:91:c4:03:a0:6f:b6:34:f9:86:d3:
- b3:76:54:98:f4:4a:81:b3:53:9d:4d:40:ec:e5:77:13:45:af:
- 5b:aa:1f:d8:2f:4c:82:7b:fe:2a:c4:58:bb:4f:fc:9e:fd:03:
- 65:1a:2a:0e:c3:a5:20:16:94:6b:79:a6:a2:12:b4:bb:1a:a4:
- 23:7a:5f:f0:ae:84:24:e4:f3:2b:fb:8a:24:a3:27:98:65:da:
- 30:75:76:fc:19:91:e8:db:eb:9b:3f:32:bf:40:97:07:26:ba:
- cc:f3:94:85:4a:7a:27:93:cf:90:42:d4:b8:5b:16:a6:e7:cb:
- 40:03:dd:79
-SHA1 Fingerprint=61:57:3A:11:DF:0E:D8:7E:D5:92:65:22:EA:D0:56:D7:44:B3:23:71
diff --git a/luni/src/main/java/android/system/NetlinkSocketAddress.java b/luni/src/main/java/android/system/NetlinkSocketAddress.java
new file mode 100644
index 0000000..af78cd0
--- /dev/null
+++ b/luni/src/main/java/android/system/NetlinkSocketAddress.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.system;
+
+import libcore.util.Objects;
+import java.net.SocketAddress;
+
+/**
+ * Netlink socket address.
+ *
+ * Corresponds to Linux's {@code struct sockaddr_nl} from
+ * <a href="https://github.com/torvalds/linux/blob/master/include/uapi/linux/netlink.h">&lt;linux/netlink.h&gt;</a>.
+ *
+ * @hide
+ */
+public final class NetlinkSocketAddress extends SocketAddress {
+ /** port ID */
+ private final int nlPortId;
+
+ /** multicast groups mask */
+ private final int nlGroupsMask;
+
+ public NetlinkSocketAddress() {
+ this(0, 0);
+ }
+
+ public NetlinkSocketAddress(int nlPortId) {
+ this(nlPortId, 0);
+ }
+
+ public NetlinkSocketAddress(int nlPortId, int nlGroupsMask) {
+ this.nlPortId = nlPortId;
+ this.nlGroupsMask = nlGroupsMask;
+ }
+
+ public int getPortId() {
+ return nlPortId;
+ }
+
+ public int getGroupsMask() {
+ return nlGroupsMask;
+ }
+
+ @Override public String toString() {
+ return Objects.toString(this);
+ }
+}
diff --git a/luni/src/main/java/android/system/Os.java b/luni/src/main/java/android/system/Os.java
index 9d6dc1b..a1e87c8 100644
--- a/luni/src/main/java/android/system/Os.java
+++ b/luni/src/main/java/android/system/Os.java
@@ -54,6 +54,8 @@ public final class Os {
*/
public static void bind(FileDescriptor fd, InetAddress address, int port) throws ErrnoException, SocketException { Libcore.os.bind(fd, address, port); }
+ /** @hide */ public static void bind(FileDescriptor fd, SocketAddress address) throws ErrnoException, SocketException { Libcore.os.bind(fd, address); }
+
/**
* See <a href="http://man7.org/linux/man-pages/man2/chmod.2.html">chmod(2)</a>.
*/
@@ -74,6 +76,8 @@ public final class Os {
*/
public static void connect(FileDescriptor fd, InetAddress address, int port) throws ErrnoException, SocketException { Libcore.os.connect(fd, address, port); }
+ /** @hide */ public static void connect(FileDescriptor fd, SocketAddress address) throws ErrnoException, SocketException { Libcore.os.connect(fd, address); }
+
/**
* See <a href="http://man7.org/linux/man-pages/man2/dup.2.html">dup(2)</a>.
*/
@@ -109,9 +113,9 @@ public final class Os {
*/
public static void fchown(FileDescriptor fd, int uid, int gid) throws ErrnoException { Libcore.os.fchown(fd, uid, gid); }
- /** @hide */ public static int fcntlVoid(FileDescriptor fd, int cmd) throws ErrnoException { return Libcore.os.fcntlVoid(fd, cmd); }
- /** @hide */ public static int fcntlLong(FileDescriptor fd, int cmd, long arg) throws ErrnoException { return Libcore.os.fcntlLong(fd, cmd, arg); }
/** @hide */ public static int fcntlFlock(FileDescriptor fd, int cmd, StructFlock arg) throws ErrnoException, InterruptedIOException { return Libcore.os.fcntlFlock(fd, cmd, arg); }
+ /** @hide */ public static int fcntlInt(FileDescriptor fd, int cmd, int arg) throws ErrnoException { return Libcore.os.fcntlInt(fd, cmd, arg); }
+ /** @hide */ public static int fcntlVoid(FileDescriptor fd, int cmd) throws ErrnoException { return Libcore.os.fcntlVoid(fd, cmd); }
/**
* See <a href="http://man7.org/linux/man-pages/man2/fdatasync.2.html">fdatasync(2)</a>.
@@ -171,6 +175,11 @@ public final class Os {
public static SocketAddress getpeername(FileDescriptor fd) throws ErrnoException { return Libcore.os.getpeername(fd); }
/**
+ * See <a href="http://man7.org/linux/man-pages/man2/getpgid.2.html">getpgid(2)</a>.
+ */
+ /** @hide */ public static int getpgid(int pid) throws ErrnoException { return Libcore.os.getpgid(pid); }
+
+ /**
* See <a href="http://man7.org/linux/man-pages/man2/getpid.2.html">getpid(2)</a>.
*/
public static int getpid() { return Libcore.os.getpid(); }
@@ -206,6 +215,8 @@ public final class Os {
*/
public static int getuid() { return Libcore.os.getuid(); }
+ /** @hide */ public static int getxattr(String path, String name, byte[] outValue) throws ErrnoException { return Libcore.os.getxattr(path, name, outValue); }
+
/**
* See <a href="http://man7.org/linux/man-pages/man3/if_indextoname.3.html">if_indextoname(3)</a>.
*/
@@ -302,10 +313,16 @@ public final class Os {
/**
* See <a href="http://man7.org/linux/man-pages/man2/pipe.2.html">pipe(2)</a>.
*/
- public static FileDescriptor[] pipe() throws ErrnoException { return Libcore.os.pipe(); }
+ public static FileDescriptor[] pipe() throws ErrnoException { return Libcore.os.pipe2(0); }
+
+ /** @hide */ public static FileDescriptor[] pipe2(int flags) throws ErrnoException { return Libcore.os.pipe2(flags); }
/**
* See <a href="http://man7.org/linux/man-pages/man2/poll.2.html">poll(2)</a>.
+ *
+ * <p>Note that in Lollipop this could throw an {@code ErrnoException} with {@code EINTR}.
+ * In later releases, the implementation will automatically just restart the system call with
+ * an appropriately reduced timeout.
*/
public static int poll(StructPollfd[] fds, int timeoutMs) throws ErrnoException { return Libcore.os.poll(fds, timeoutMs); }
@@ -374,6 +391,8 @@ public final class Os {
*/
public static void remove(String path) throws ErrnoException { Libcore.os.remove(path); }
+ /** @hide */ public static void removexattr(String path, String name) throws ErrnoException { Libcore.os.removexattr(path, name); }
+
/**
* See <a href="http://man7.org/linux/man-pages/man2/rename.2.html">rename(2)</a>.
*/
@@ -395,6 +414,11 @@ public final class Os {
public static int sendto(FileDescriptor fd, byte[] bytes, int byteOffset, int byteCount, int flags, InetAddress inetAddress, int port) throws ErrnoException, SocketException { return Libcore.os.sendto(fd, bytes, byteOffset, byteCount, flags, inetAddress, port); }
/**
+ * See <a href="http://man7.org/linux/man-pages/man2/sendto.2.html">sendto(2)</a>.
+ */
+ /** @hide */ public static int sendto(FileDescriptor fd, byte[] bytes, int byteOffset, int byteCount, int flags, SocketAddress address) throws ErrnoException, SocketException { return Libcore.os.sendto(fd, bytes, byteOffset, byteCount, flags, address); }
+
+ /**
* See <a href="http://man7.org/linux/man-pages/man2/setegid.2.html">setegid(2)</a>.
*/
public static void setegid(int egid) throws ErrnoException { Libcore.os.setegid(egid); }
@@ -415,6 +439,21 @@ public final class Os {
public static void setgid(int gid) throws ErrnoException { Libcore.os.setgid(gid); }
/**
+ * See <a href="http://man7.org/linux/man-pages/man2/setpgid.2.html">setpgid(2)</a>.
+ */
+ /** @hide */ public static void setpgid(int pid, int pgid) throws ErrnoException { Libcore.os.setpgid(pid, pgid); }
+
+ /**
+ * See <a href="http://man7.org/linux/man-pages/man2/setregid.2.html">setregid(2)</a>.
+ */
+ /** @hide */ public static void setregid(int rgid, int egid) throws ErrnoException { Libcore.os.setregid(rgid, egid); }
+
+ /**
+ * See <a href="http://man7.org/linux/man-pages/man2/setreuid.2.html">setreuid(2)</a>.
+ */
+ /** @hide */ public static void setreuid(int ruid, int euid) throws ErrnoException { Libcore.os.setreuid(ruid, euid); }
+
+ /**
* See <a href="http://man7.org/linux/man-pages/man2/setsid.2.html">setsid(2)</a>.
*/
public static int setsid() throws ErrnoException { return Libcore.os.setsid(); }
@@ -433,6 +472,8 @@ public final class Os {
*/
public static void setuid(int uid) throws ErrnoException { Libcore.os.setuid(uid); }
+ /** @hide */ public static void setxattr(String path, String name, byte[] value, int flags) throws ErrnoException { Libcore.os.setxattr(path, name, value, flags); };
+
/**
* See <a href="http://man7.org/linux/man-pages/man2/shutdown.2.html">shutdown(2)</a>.
*/
diff --git a/luni/src/main/java/android/system/OsConstants.java b/luni/src/main/java/android/system/OsConstants.java
index c758eb7..8832f3d 100644
--- a/luni/src/main/java/android/system/OsConstants.java
+++ b/luni/src/main/java/android/system/OsConstants.java
@@ -95,6 +95,8 @@ public final class OsConstants {
public static final int AF_INET = placeholder();
public static final int AF_INET6 = placeholder();
+ /** @hide */ public static final int AF_NETLINK = placeholder();
+ /** @hide */ public static final int AF_PACKET = placeholder();
public static final int AF_UNIX = placeholder();
public static final int AF_UNSPEC = placeholder();
public static final int AI_ADDRCONFIG = placeholder();
@@ -104,6 +106,8 @@ public final class OsConstants {
public static final int AI_NUMERICSERV = placeholder();
public static final int AI_PASSIVE = placeholder();
public static final int AI_V4MAPPED = placeholder();
+ /** @hide */ public static final int ARPHRD_ETHER = placeholder();
+ /** @hide */ public static final int ARPHRD_LOOPBACK = placeholder();
public static final int CAP_AUDIT_CONTROL = placeholder();
public static final int CAP_AUDIT_WRITE = placeholder();
public static final int CAP_BLOCK_SUSPEND = placeholder();
@@ -203,6 +207,7 @@ public final class OsConstants {
public static final int ENOLINK = placeholder();
public static final int ENOMEM = placeholder();
public static final int ENOMSG = placeholder();
+ /** @hide */ public static final int ENONET = placeholder();
public static final int ENOPROTOOPT = placeholder();
public static final int ENOSPC = placeholder();
public static final int ENOSR = placeholder();
@@ -227,6 +232,9 @@ public final class OsConstants {
public static final int ESPIPE = placeholder();
public static final int ESRCH = placeholder();
public static final int ESTALE = placeholder();
+ /** @hide */ public static final int ETH_P_ARP = placeholder();
+ /** @hide */ public static final int ETH_P_IP = placeholder();
+ /** @hide */ public static final int ETH_P_IPV6 = placeholder();
public static final int ETIME = placeholder();
public static final int ETIMEDOUT = placeholder();
public static final int ETXTBSY = placeholder();
@@ -324,6 +332,7 @@ public final class OsConstants {
public static final int MS_ASYNC = placeholder();
public static final int MS_INVALIDATE = placeholder();
public static final int MS_SYNC = placeholder();
+ /** @hide */ public static final int NETLINK_ROUTE = placeholder();
public static final int NI_DGRAM = placeholder();
public static final int NI_NAMEREQD = placeholder();
public static final int NI_NOFQDN = placeholder();
@@ -331,6 +340,7 @@ public final class OsConstants {
public static final int NI_NUMERICSERV = placeholder();
public static final int O_ACCMODE = placeholder();
public static final int O_APPEND = placeholder();
+ /** @hide */ public static final int O_CLOEXEC = placeholder();
public static final int O_CREAT = placeholder();
public static final int O_EXCL = placeholder();
public static final int O_NOCTTY = placeholder();
@@ -364,6 +374,19 @@ public final class OsConstants {
public static final int RT_SCOPE_NOWHERE = placeholder();
public static final int RT_SCOPE_SITE = placeholder();
public static final int RT_SCOPE_UNIVERSE = placeholder();
+ /** @hide */ public static final int RTMGRP_IPV4_IFADDR = placeholder();
+ /** @hide */ public static final int RTMGRP_IPV4_MROUTE = placeholder();
+ /** @hide */ public static final int RTMGRP_IPV4_ROUTE = placeholder();
+ /** @hide */ public static final int RTMGRP_IPV4_RULE = placeholder();
+ /** @hide */ public static final int RTMGRP_IPV6_IFADDR = placeholder();
+ /** @hide */ public static final int RTMGRP_IPV6_IFINFO = placeholder();
+ /** @hide */ public static final int RTMGRP_IPV6_MROUTE = placeholder();
+ /** @hide */ public static final int RTMGRP_IPV6_PREFIX = placeholder();
+ /** @hide */ public static final int RTMGRP_IPV6_ROUTE = placeholder();
+ /** @hide */ public static final int RTMGRP_LINK = placeholder();
+ /** @hide */ public static final int RTMGRP_NEIGH = placeholder();
+ /** @hide */ public static final int RTMGRP_NOTIFY = placeholder();
+ /** @hide */ public static final int RTMGRP_TC = placeholder();
public static final int SEEK_CUR = placeholder();
public static final int SEEK_END = placeholder();
public static final int SEEK_SET = placeholder();
@@ -433,6 +456,15 @@ public final class OsConstants {
public static final int STDERR_FILENO = placeholder();
public static final int STDIN_FILENO = placeholder();
public static final int STDOUT_FILENO = placeholder();
+ public static final int ST_MANDLOCK = placeholder();
+ public static final int ST_NOATIME = placeholder();
+ public static final int ST_NODEV = placeholder();
+ public static final int ST_NODIRATIME = placeholder();
+ public static final int ST_NOEXEC = placeholder();
+ public static final int ST_NOSUID = placeholder();
+ public static final int ST_RDONLY = placeholder();
+ public static final int ST_RELATIME = placeholder();
+ public static final int ST_SYNCHRONOUS = placeholder();
public static final int S_IFBLK = placeholder();
public static final int S_IFCHR = placeholder();
public static final int S_IFDIR = placeholder();
@@ -464,6 +496,8 @@ public final class OsConstants {
public static final int WSTOPPED = placeholder();
public static final int WUNTRACED = placeholder();
public static final int W_OK = placeholder();
+ /** @hide */ public static final int XATTR_CREATE = placeholder();
+ /** @hide */ public static final int XATTR_REPLACE = placeholder();
public static final int X_OK = placeholder();
public static final int _SC_2_CHAR_TERM = placeholder();
public static final int _SC_2_C_BIND = placeholder();
@@ -752,6 +786,9 @@ public final class OsConstants {
if (errno == ENOMSG) {
return "ENOMSG";
}
+ if (errno == ENONET) {
+ return "ENONET";
+ }
if (errno == ENOPROTOOPT) {
return "ENOPROTOOPT";
}
diff --git a/luni/src/main/java/android/system/PacketSocketAddress.java b/luni/src/main/java/android/system/PacketSocketAddress.java
new file mode 100644
index 0000000..510771c
--- /dev/null
+++ b/luni/src/main/java/android/system/PacketSocketAddress.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.system;
+
+import libcore.util.Objects;
+import java.net.SocketAddress;
+
+/**
+ * Packet socket address.
+ *
+ * Corresponds to Linux's {@code struct sockaddr_ll}.
+ *
+ * @hide
+ */
+public final class PacketSocketAddress extends SocketAddress {
+ /** Protocol. An Ethernet protocol type, e.g., {@code ETH_P_IPV6}. */
+ public short sll_protocol;
+
+ /** Interface index. */
+ public int sll_ifindex;
+
+ /** ARP hardware type. One of the {@code ARPHRD_*} constants. */
+ public short sll_hatype;
+
+ /** Packet type. One of the {@code PACKET_*} constants, such as {@code PACKET_OTHERHOST}. */
+ public byte sll_pkttype;
+
+ /** Hardware address. */
+ public byte[] sll_addr;
+
+ /** Constructs a new PacketSocketAddress. */
+ public PacketSocketAddress(short sll_protocol, int sll_ifindex,
+ short sll_hatype, byte sll_pkttype, byte[] sll_addr) {
+ this.sll_protocol = sll_protocol;
+ this.sll_ifindex = sll_ifindex;
+ this.sll_hatype = sll_hatype;
+ this.sll_pkttype = sll_pkttype;
+ this.sll_addr = sll_addr;
+ }
+
+ /** Constructs a new PacketSocketAddress suitable for binding to. */
+ public PacketSocketAddress(short sll_protocol, int sll_ifindex) {
+ this(sll_protocol, sll_ifindex, (short) 0, (byte) 0, null);
+ }
+
+ /** Constructs a new PacketSocketAddress suitable for sending to. */
+ public PacketSocketAddress(int sll_ifindex, byte[] sll_addr) {
+ this((short) 0, sll_ifindex, (short) 0, (byte) 0, sll_addr);
+ }
+}
diff --git a/luni/src/main/java/java/io/BufferedInputStream.java b/luni/src/main/java/java/io/BufferedInputStream.java
index 85236b6..ec43720 100644
--- a/luni/src/main/java/java/io/BufferedInputStream.java
+++ b/luni/src/main/java/java/io/BufferedInputStream.java
@@ -150,7 +150,7 @@ public class BufferedInputStream extends FilterInputStream {
if (result > 0) {
markpos = -1;
pos = 0;
- count = result == -1 ? 0 : result;
+ count = result;
}
return result;
}
diff --git a/luni/src/main/java/java/io/File.java b/luni/src/main/java/java/io/File.java
index d107c28..0592345 100644
--- a/luni/src/main/java/java/io/File.java
+++ b/luni/src/main/java/java/io/File.java
@@ -57,12 +57,6 @@ public class File implements Serializable, Comparable<File> {
private static final long serialVersionUID = 301077366599181567L;
/**
- * Reusing a Random makes temporary filenames slightly harder to predict.
- * (Random is thread-safe.)
- */
- private static final Random tempFileRandom = new Random();
-
- /**
* The system-dependent character used to separate components in filenames ('/').
* Use of this (rather than hard-coding '/') helps portability to other operating systems.
*
@@ -129,6 +123,8 @@ public class File implements Serializable, Comparable<File> {
*
* @param path
* the path to be used for the file.
+ * @throws NullPointerException
+ * if {@code path} is {@code null}.
*/
public File(String path) {
this.path = fixSlashes(path);
@@ -167,6 +163,8 @@ public class File implements Serializable, Comparable<File> {
* @param uri
* the Unified Resource Identifier that is used to construct this
* file.
+ * @throws NullPointerException
+ * if {@code uri == null}.
* @throws IllegalArgumentException
* if {@code uri} does not comply with the conditions above.
* @see #toURI
@@ -1002,7 +1000,7 @@ public class File implements Serializable, Comparable<File> {
}
File result;
do {
- result = new File(tmpDirFile, prefix + tempFileRandom.nextInt() + suffix);
+ result = new File(tmpDirFile, prefix + Math.randomIntInternal() + suffix);
} while (!result.createNewFile());
return result;
}
diff --git a/luni/src/main/java/java/io/FileDescriptor.java b/luni/src/main/java/java/io/FileDescriptor.java
index eba0e4d..be94c52 100644
--- a/luni/src/main/java/java/io/FileDescriptor.java
+++ b/luni/src/main/java/java/io/FileDescriptor.java
@@ -108,7 +108,7 @@ public final class FileDescriptor {
/**
* @hide internal use only
*/
- public boolean isSocket() {
+ public final boolean isSocket$() {
return isSocket(descriptor);
}
diff --git a/luni/src/main/java/java/io/InputStreamReader.java b/luni/src/main/java/java/io/InputStreamReader.java
index d57b916..a4cacf2 100644
--- a/luni/src/main/java/java/io/InputStreamReader.java
+++ b/luni/src/main/java/java/io/InputStreamReader.java
@@ -101,7 +101,9 @@ public class InputStreamReader extends Reader {
*/
public InputStreamReader(InputStream in, CharsetDecoder dec) {
super(in);
- dec.averageCharsPerByte();
+ if (dec == null) {
+ throw new NullPointerException("dec == null");
+ }
this.in = in;
decoder = dec;
bytes.limit(0);
diff --git a/luni/src/main/java/java/io/ObjectInputStream.java b/luni/src/main/java/java/io/ObjectInputStream.java
index 3a89b52..cd267b2 100644
--- a/luni/src/main/java/java/io/ObjectInputStream.java
+++ b/luni/src/main/java/java/io/ObjectInputStream.java
@@ -1977,7 +1977,7 @@ public class ObjectInputStream extends InputStream implements ObjectInput, Objec
// original/outside caller
if (++nestedLevels == 1) {
// Remember the caller's class loader
- callerClassLoader = VMStack.getClosestUserClassLoader(bootstrapLoader, systemLoader);
+ callerClassLoader = VMStack.getClosestUserClassLoader();
}
result = readNonPrimitiveContent(unshared);
@@ -2014,9 +2014,6 @@ public class ObjectInputStream extends InputStream implements ObjectInput, Objec
return result;
}
- private static final ClassLoader bootstrapLoader = Object.class.getClassLoader();
- private static final ClassLoader systemLoader = ClassLoader.getSystemClassLoader();
-
/**
* Method to be overridden by subclasses to read the next object from the
* source stream.
@@ -2258,8 +2255,6 @@ public class ObjectInputStream extends InputStream implements ObjectInput, Objec
if (cls == null) {
// not primitive class
- // Use the first non-null ClassLoader on the stack. If null, use
- // the system class loader
cls = Class.forName(className, false, callerClassLoader);
}
}
diff --git a/luni/src/main/java/java/io/ObjectStreamField.java b/luni/src/main/java/java/io/ObjectStreamField.java
index 78a6903..2a9b107 100644
--- a/luni/src/main/java/java/io/ObjectStreamField.java
+++ b/luni/src/main/java/java/io/ObjectStreamField.java
@@ -58,13 +58,7 @@ public class ObjectStreamField implements Comparable<Object> {
* if {@code name} or {@code cl} is {@code null}.
*/
public ObjectStreamField(String name, Class<?> cl) {
- if (name == null) {
- throw new NullPointerException("name == null");
- } else if (cl == null) {
- throw new NullPointerException("cl == null");
- }
- this.name = name;
- this.type = new WeakReference<Class<?>>(cl);
+ this(name, cl, false);
}
/**
diff --git a/luni/src/main/java/java/io/OutputStreamWriter.java b/luni/src/main/java/java/io/OutputStreamWriter.java
index bc8710d..8a639e7 100644
--- a/luni/src/main/java/java/io/OutputStreamWriter.java
+++ b/luni/src/main/java/java/io/OutputStreamWriter.java
@@ -116,7 +116,10 @@ public class OutputStreamWriter extends Writer {
*/
public OutputStreamWriter(OutputStream out, CharsetEncoder charsetEncoder) {
super(out);
- charsetEncoder.charset();
+ if (charsetEncoder == null) {
+ throw new NullPointerException("charsetEncoder == null");
+ }
+
this.out = out;
encoder = charsetEncoder;
}
diff --git a/luni/src/main/java/java/io/RandomAccessFile.java b/luni/src/main/java/java/io/RandomAccessFile.java
index da99765..0e4fa4f 100644
--- a/luni/src/main/java/java/io/RandomAccessFile.java
+++ b/luni/src/main/java/java/io/RandomAccessFile.java
@@ -160,7 +160,6 @@ public class RandomAccessFile implements DataInput, DataOutput, Closeable {
synchronized (this) {
if (channel != null && channel.isOpen()) {
channel.close();
- channel = null;
}
IoBridge.closeAndSignalBlockedThreads(fd);
}
@@ -185,6 +184,10 @@ public class RandomAccessFile implements DataInput, DataOutput, Closeable {
* changes made to this file's file pointer offset are also visible in the
* file channel's position and vice versa.
*
+ * Closing the channel closes the RandomAccessFile as well. The instance
+ * of FileChannel returned is always the same even if the RandomAccessFile
+ * or the FileChannel have been closed.
+ *
* @return this file's file channel instance.
*/
public final synchronized FileChannel getChannel() {
diff --git a/luni/src/main/java/java/lang/IllegalAccessError.java b/luni/src/main/java/java/lang/IllegalAccessError.java
index 3f7cf86..582de12 100644
--- a/luni/src/main/java/java/lang/IllegalAccessError.java
+++ b/luni/src/main/java/java/lang/IllegalAccessError.java
@@ -18,8 +18,14 @@
package java.lang;
/**
- * Thrown when the VM notices that a program tries access a field
- * which is not accessible from where it is referenced.
+ * Thrown when the runtime notices that a program tries to access a class or member
+ * which is not accessible from where it is referenced. Some examples are:
+ * <ul>
+ * <li>The superclass or an implemented interface is not accessible in the subclass.
+ * <li>Reading or writing an inaccessible field, e.g., a private field in another class.
+ * <li>Invoking an inaccessible method, e.g., the constructor of an inaccessible class,
+ * or a private method of another class.
+ * </ul>
* <p>
* Note that this can only occur when inconsistent class files have been loaded.
*/
diff --git a/luni/src/main/java/java/lang/Math.java b/luni/src/main/java/java/lang/Math.java
index 86df784..7203566 100644
--- a/luni/src/main/java/java/lang/Math.java
+++ b/luni/src/main/java/java/lang/Math.java
@@ -35,7 +35,9 @@ public final class Math {
*/
public static final double PI = 3.141592653589793;
- private static Random random;
+ private static class NoImagePreloadHolder {
+ private static final Random INSTANCE = new Random();
+ }
/**
* Prevents this class from being instantiated.
@@ -875,11 +877,25 @@ public final class Math {
*
* @return a pseudo-random number.
*/
- public static synchronized double random() {
- if (random == null) {
- random = new Random();
- }
- return random.nextDouble();
+ public static double random() {
+ return NoImagePreloadHolder.INSTANCE.nextDouble();
+ }
+
+ /**
+ * Set the seed for the pseudo random generator used by {@link #random()}
+ * and {@link #randomIntInternal()}.
+ *
+ * @hide for internal use only.
+ */
+ public static void setRandomSeedInternal(long seed) {
+ NoImagePreloadHolder.INSTANCE.setSeed(seed);
+ }
+
+ /**
+ * @hide for internal use only.
+ */
+ public static int randomIntInternal() {
+ return NoImagePreloadHolder.INSTANCE.nextInt();
}
/**
diff --git a/luni/src/main/java/java/lang/Package.java b/luni/src/main/java/java/lang/Package.java
index 7e30883..3c6c39c 100644
--- a/luni/src/main/java/java/lang/Package.java
+++ b/luni/src/main/java/java/lang/Package.java
@@ -51,6 +51,7 @@ import java.net.URL;
public class Package implements AnnotatedElement {
private static final Annotation[] NO_ANNOTATIONS = new Annotation[0];
+ private final ClassLoader classLoader;
private final String name;
private final String specTitle;
private final String specVersion;
@@ -60,8 +61,10 @@ public class Package implements AnnotatedElement {
private final String implVendor;
private final URL sealBase;
- Package(String name, String specTitle, String specVersion, String specVendor,
- String implTitle, String implVersion, String implVendor, URL sealBase) {
+ Package(ClassLoader classLoader, String name, String specTitle, String specVersion,
+ String specVendor, String implTitle, String implVersion, String implVendor,
+ URL sealBase) {
+ this.classLoader = classLoader;
this.name = name;
this.specTitle = specTitle;
this.specVersion = specVersion;
@@ -96,7 +99,8 @@ public class Package implements AnnotatedElement {
*/
public Annotation[] getAnnotations() {
try {
- Class<?> c = Class.forName(getName() + ".package-info");
+ Class<?> c = Class.forName(getName() + ".package-info", false /* initialize */,
+ classLoader);
return c.getAnnotations();
} catch (Exception ex) {
return NO_ANNOTATIONS;
@@ -175,11 +179,11 @@ public class Package implements AnnotatedElement {
* @see ClassLoader#getPackage(java.lang.String)
*/
public static Package getPackage(String packageName) {
- ClassLoader classloader = VMStack.getCallingClassLoader();
- if (classloader == null) {
- classloader = ClassLoader.getSystemClassLoader();
+ ClassLoader classLoader = VMStack.getCallingClassLoader();
+ if (classLoader == null) {
+ classLoader = ClassLoader.getSystemClassLoader();
}
- return classloader.getPackage(packageName);
+ return classLoader.getPackage(packageName);
}
/**
@@ -189,11 +193,11 @@ public class Package implements AnnotatedElement {
* @see ClassLoader#getPackages
*/
public static Package[] getPackages() {
- ClassLoader classloader = VMStack.getCallingClassLoader();
- if (classloader == null) {
- classloader = ClassLoader.getSystemClassLoader();
+ ClassLoader classLoader = VMStack.getCallingClassLoader();
+ if (classLoader == null) {
+ classLoader = ClassLoader.getSystemClassLoader();
}
- return classloader.getPackages();
+ return classLoader.getPackages();
}
/**
diff --git a/luni/src/main/java/java/lang/Runtime.java b/luni/src/main/java/java/lang/Runtime.java
index a3cb83e..f1f6438 100644
--- a/luni/src/main/java/java/lang/Runtime.java
+++ b/luni/src/main/java/java/lang/Runtime.java
@@ -34,6 +34,7 @@ package java.lang;
import dalvik.system.BaseDexClassLoader;
import dalvik.system.VMDebug;
+import dalvik.system.VMRuntime;
import dalvik.system.VMStack;
import java.io.File;
import java.io.IOException;
@@ -418,8 +419,14 @@ public class Runtime {
// So, find out what the native library search path is for the ClassLoader in question...
String ldLibraryPath = null;
- if (loader != null && loader instanceof BaseDexClassLoader) {
- ldLibraryPath = ((BaseDexClassLoader) loader).getLdLibraryPath();
+ String dexPath = null;
+ if (loader == null) {
+ // We use the given library path for the boot class loader. This is the path
+ // also used in loadLibraryName if loader is null.
+ ldLibraryPath = System.getProperty("java.library.path");
+ } else if (loader instanceof BaseDexClassLoader) {
+ BaseDexClassLoader dexClassLoader = (BaseDexClassLoader) loader;
+ ldLibraryPath = dexClassLoader.getLdLibraryPath();
}
// nativeLoad should be synchronized so there's only one LD_LIBRARY_PATH in use regardless
// of how many ClassLoaders are in the system, but dalvik doesn't support synchronized
@@ -430,23 +437,21 @@ public class Runtime {
}
// TODO: should be synchronized, but dalvik doesn't support synchronized internal natives.
- private static native String nativeLoad(String filename, ClassLoader loader, String ldLibraryPath);
+ private static native String nativeLoad(String filename, ClassLoader loader,
+ String ldLibraryPath);
/**
- * Provides a hint to the VM that it would be useful to attempt
+ * Provides a hint to the runtime that it would be useful to attempt
* to perform any outstanding object finalization.
*/
public void runFinalization() {
- try {
- FinalizerReference.finalizeAllEnqueued();
- } catch (InterruptedException e) {
- Thread.currentThread().interrupt();
- }
+ // 0 for no timeout.
+ VMRuntime.runFinalization(0);
}
/**
* Sets the flag that indicates whether all objects are finalized when the
- * VM is about to exit. Note that all finalization which occurs
+ * runtime is about to exit. Note that all finalization which occurs
* when the system is exiting is performed after all running threads have
* been terminated.
*
diff --git a/luni/src/main/java/java/lang/StrictMath.java b/luni/src/main/java/java/lang/StrictMath.java
index f409c06..2e848f2 100644
--- a/luni/src/main/java/java/lang/StrictMath.java
+++ b/luni/src/main/java/java/lang/StrictMath.java
@@ -15,6 +15,18 @@
* limitations under the License.
*/
+/*
+ * acos, asin, atan, cosh, sinh, tanh, exp, expm1, log, log10, log1p, and cbrt
+ * have been implemented with the following license.
+ * ====================================================
+ * Copyright (C) 2004 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
package java.lang;
/**
@@ -102,6 +114,21 @@ public final class StrictMath {
return Math.abs(l);
}
+ private static final double PIO2_HI = 1.57079632679489655800e+00;
+ private static final double PIO2_LO = 6.12323399573676603587e-17;
+ private static final double PS0 = 1.66666666666666657415e-01;
+ private static final double PS1 = -3.25565818622400915405e-01;
+ private static final double PS2 = 2.01212532134862925881e-01;
+ private static final double PS3 = -4.00555345006794114027e-02;
+ private static final double PS4 = 7.91534994289814532176e-04;
+ private static final double PS5 = 3.47933107596021167570e-05;
+ private static final double QS1 = -2.40339491173441421878e+00;
+ private static final double QS2 = 2.02094576023350569471e+00;
+ private static final double QS3 = -6.88283971605453293030e-01;
+ private static final double QS4 = 7.70381505559019352791e-02;
+ private static final double HUGE = 1.000e+300;
+ private static final double PIO4_HI = 7.85398163397448278999e-01;
+
/**
* Returns the closest double approximation of the arc cosine of the
* argument within the range {@code [0..pi]}.
@@ -113,11 +140,62 @@ public final class StrictMath {
* <li>{@code acos(NaN) = NaN}</li>
* </ul>
*
- * @param d
+ * @param x
* the value to compute arc cosine of.
* @return the arc cosine of the argument.
*/
- public static native double acos(double d);
+ public static double acos(double x) {
+ double z, p, q, r, w, s, c, df;
+ int hx, ix;
+ final long bits = Double.doubleToRawLongBits(x);
+ hx = (int) (bits >>> 32);
+ ix = hx & 0x7fffffff;
+ if (ix >= 0x3ff00000) { /* |x| >= 1 */
+ if ((((ix - 0x3ff00000) | ((int) bits))) == 0) { /* |x|==1 */
+ if (hx > 0) {
+ return 0.0; /* ieee_acos(1) = 0 */
+ } else {
+ return 3.14159265358979311600e+00 + 2.0 * PIO2_LO; /* ieee_acos(-1)= pi */
+ }
+ }
+ return (x - x) / (x - x); /* ieee_acos(|x|>1) is NaN */
+ }
+
+ if (ix < 0x3fe00000) { /* |x| < 0.5 */
+ if (ix <= 0x3c600000) {
+ return PIO2_HI + PIO2_LO;/* if|x|<2**-57 */
+ }
+
+ z = x * x;
+ p = z * (PS0 + z
+ * (PS1 + z * (PS2 + z * (PS3 + z * (PS4 + z * PS5)))));
+ q = 1.00000000000000000000e+00 + z * (QS1 + z * (QS2 + z * (QS3 + z * QS4)));
+ r = p / q;
+ return PIO2_HI - (x - (PIO2_LO - x * r));
+ } else if (hx < 0) { /* x < -0.5 */
+ z = (1.00000000000000000000e+00 + x) * 0.5;
+ p = z * (PS0 + z
+ * (PS1 + z * (PS2 + z * (PS3 + z * (PS4 + z * PS5)))));
+ q = 1.00000000000000000000e+00 + z * (QS1 + z * (QS2 + z * (QS3 + z * QS4)));
+ s = StrictMath.sqrt(z);
+ r = p / q;
+ w = r * s - PIO2_LO;
+ return 3.14159265358979311600e+00 - 2.0 * (s + w);
+ } else { /* x > 0.5 */
+ z = (1.00000000000000000000e+00 - x) * 0.5;
+ s = StrictMath.sqrt(z);
+ df = s;
+ df = Double.longBitsToDouble(
+ Double.doubleToRawLongBits(df) & 0xffffffffL << 32);
+ c = (z - df * df) / (s + df);
+ p = z * (PS0 + z
+ * (PS1 + z * (PS2 + z * (PS3 + z * (PS4 + z * PS5)))));
+ q = 1.00000000000000000000e+00 + z * (QS1 + z * (QS2 + z * (QS3 + z * QS4)));
+ r = p / q;
+ w = r * s + c;
+ return 2.0 * (df + w);
+ }
+ }
/**
* Returns the closest double approximation of the arc sine of the argument
@@ -130,11 +208,75 @@ public final class StrictMath {
* <li>{@code asin(NaN) = NaN}</li>
* </ul>
*
- * @param d
+ * @param x
* the value whose arc sine has to be computed.
* @return the arc sine of the argument.
*/
- public static native double asin(double d);
+ public static double asin(double x) {
+ double t, w, p, q, c, r, s;
+ int hx, ix;
+ final long bits = Double.doubleToRawLongBits(x);
+ hx = (int) (bits >>> 32);
+ ix = hx & 0x7fffffff;
+ if (ix >= 0x3ff00000) { /* |x|>= 1 */
+ if ((((ix - 0x3ff00000) | ((int) bits))) == 0) {
+ /* ieee_asin(1)=+-pi/2 with inexact */
+ return x * PIO2_HI + x * PIO2_LO;
+ }
+ return (x - x) / (x - x); /* ieee_asin(|x|>1) is NaN */
+ } else if (ix < 0x3fe00000) { /* |x|<0.5 */
+ if (ix < 0x3e400000) { /* if |x| < 2**-27 */
+ if (HUGE + x > 1.00000000000000000000e+00) {
+ return x;/* return x with inexact if x!=0 */
+ }
+ } else {
+ t = x * x;
+ p = t * (PS0 + t
+ * (PS1 + t * (PS2 + t * (PS3 + t * (PS4 + t * PS5)))));
+ q = 1.00000000000000000000e+00 + t * (QS1 + t * (QS2 + t * (QS3 + t * QS4)));
+ w = p / q;
+ return x + x * w;
+ }
+ }
+ /* 1> |x|>= 0.5 */
+ w = 1.00000000000000000000e+00 - Math.abs(x);
+ t = w * 0.5;
+ p = t * (PS0 + t * (PS1 + t * (PS2 + t * (PS3 + t * (PS4 + t * PS5)))));
+ q = 1.00000000000000000000e+00 + t * (QS1 + t * (QS2 + t * (QS3 + t * QS4)));
+ s = StrictMath.sqrt(t);
+ if (ix >= 0x3FEF3333) { /* if |x| > 0.975 */
+ w = p / q;
+ t = PIO2_HI - (2.0 * (s + s * w) - PIO2_LO);
+ } else {
+ w = s;
+ w = Double.longBitsToDouble(
+ Double.doubleToRawLongBits(w) & 0xffffffffL << 32);
+ c = (t - w * w) / (s + w);
+ r = p / q;
+ p = 2.0 * s * r - (PIO2_LO - 2.0 * c);
+ q = PIO4_HI - 2.0 * w;
+ t = PIO4_HI - (p - q);
+ }
+ return (hx > 0) ? t : -t;
+ }
+
+ private static final double[] ATANHI = { 4.63647609000806093515e-01,
+ 7.85398163397448278999e-01, 9.82793723247329054082e-01,
+ 1.57079632679489655800e+00 };
+ private static final double[] ATANLO = { 2.26987774529616870924e-17,
+ 3.06161699786838301793e-17, 1.39033110312309984516e-17,
+ 6.12323399573676603587e-17 };
+ private static final double AT0 = 3.33333333333329318027e-01;
+ private static final double AT1 = -1.99999999998764832476e-01;
+ private static final double AT2 = 1.42857142725034663711e-01;
+ private static final double AT3 = -1.11111104054623557880e-01;
+ private static final double AT4 = 9.09088713343650656196e-02;
+ private static final double AT5 = -7.69187620504482999495e-02;
+ private static final double AT6 = 6.66107313738753120669e-02;
+ private static final double AT7= -5.83357013379057348645e-02;
+ private static final double AT8 = 4.97687799461593236017e-02;
+ private static final double AT9 = -3.65315727442169155270e-02;
+ private static final double AT10 = 1.62858201153657823623e-02;
/**
* Returns the closest double approximation of the arc tangent of the
@@ -149,11 +291,73 @@ public final class StrictMath {
* <li>{@code atan(NaN) = NaN}</li>
* </ul>
*
- * @param d
+ * @param x
* the value whose arc tangent has to be computed.
* @return the arc tangent of the argument.
*/
- public static native double atan(double d);
+ public static double atan(double x) {
+ double w, s1, s2, z;
+ int ix, hx, id;
+
+ final long bits = Double.doubleToRawLongBits(x);
+ hx = (int) (bits >>> 32);
+ ix = hx & 0x7fffffff;
+ if (ix >= 0x44100000) { /* if |x| >= 2^66 */
+ if (ix > 0x7ff00000 || (ix == 0x7ff00000 && (((int) bits) != 0))) {
+ return x + x; /* NaN */
+ }
+ if (hx > 0) {
+ return ATANHI[3] + ATANLO[3];
+ } else {
+ return -ATANHI[3] - ATANLO[3];
+ }
+ }
+ if (ix < 0x3fdc0000) { /* |x| < 0.4375 */
+ if (ix < 0x3e200000) { /* |x| < 2^-29 */
+ if (HUGE + x > 1.00000000000000000000e+00) {
+ return x; /* raise inexact */
+ }
+ }
+ id = -1;
+ } else {
+ x = Math.abs(x);
+ if (ix < 0x3ff30000) { /* |x| < 1.1875 */
+ if (ix < 0x3fe60000) { /* 7/16 <=|x|<11/16 */
+ id = 0;
+ x = (2.0 * x - 1.00000000000000000000e+00) / (2.0 + x);
+ } else { /* 11/16<=|x|< 19/16 */
+ id = 1;
+ x = (x - 1.00000000000000000000e+00) / (x + 1.00000000000000000000e+00);
+ }
+ } else {
+ if (ix < 0x40038000) { /* |x| < 2.4375 */
+ id = 2;
+ x = (x - 1.5) / (1.00000000000000000000e+00 + 1.5 * x);
+ } else { /* 2.4375 <= |x| < 2^66 */
+ id = 3;
+ x = -1.0 / x;
+ }
+ }
+ }
+
+ /* end of argument reduction */
+ z = x * x;
+ w = z * z;
+ /* break sum from i=0 to 10 aT[i]z**(i+1) into odd and even poly */
+ s1 = z * (AT0 + w * (AT2 + w
+ * (AT4 + w * (AT6 + w * (AT8 + w * AT10)))));
+ s2 = w * (AT1 + w * (AT3 + w * (AT5 + w * (AT7 + w * AT9))));
+ if (id < 0) {
+ return x - x * (s1 + s2);
+ } else {
+ z = ATANHI[id] - ((x * (s1 + s2) - ATANLO[id]) - x);
+ return (hx < 0) ? -z : z;
+ }
+ }
+
+ private static final double PI_O_4 = 7.8539816339744827900E-01;
+ private static final double PI_O_2 = 1.5707963267948965580E+00;
+ private static final double PI_LO = 1.2246467991473531772E-16;
/**
* Returns the closest double approximation of the arc tangent of
@@ -192,7 +396,108 @@ public final class StrictMath {
* the denominator of the value whose atan has to be computed.
* @return the arc tangent of {@code y/x}.
*/
- public static native double atan2(double y, double x);
+ public static double atan2(double y, double x) {
+ double z;
+ int k, m, hx, hy, ix, iy;
+ int lx, ly; // watch out, should be unsigned
+
+ final long yBits = Double.doubleToRawLongBits(y);
+ final long xBits = Double.doubleToRawLongBits(x);
+
+ hx = (int) (xBits >>> 32); // __HI(x);
+ ix = hx & 0x7fffffff;
+ lx = (int) xBits; // __LO(x);
+ hy = (int) (yBits >>> 32); // __HI(y);
+ iy = hy & 0x7fffffff;
+ ly = (int) yBits; // __LO(y);
+ if (((ix | ((lx | -lx) >> 31)) > 0x7ff00000)
+ || ((iy | ((ly | -ly) >> 31)) > 0x7ff00000)) { /* x or y is NaN */
+ return x + y;
+ }
+ if ((hx - 0x3ff00000 | lx) == 0) {
+ return StrictMath.atan(y); /* x=1.0 */
+ }
+
+ m = ((hy >> 31) & 1) | ((hx >> 30) & 2); /* 2*sign(x)+sign(y) */
+
+ /* when y = 0 */
+ if ((iy | ly) == 0) {
+ switch (m) {
+ case 0:
+ case 1:
+ return y; /* ieee_atan(+-0,+anything)=+-0 */
+ case 2:
+ return 3.14159265358979311600e+00 + TINY;/* ieee_atan(+0,-anything) = pi */
+ case 3:
+ return -3.14159265358979311600e+00 - TINY;/* ieee_atan(-0,-anything) =-pi */
+ }
+ }
+ /* when x = 0 */
+ if ((ix | lx) == 0)
+ return (hy < 0) ? -PI_O_2 - TINY : PI_O_2 + TINY;
+
+ /* when x is INF */
+ if (ix == 0x7ff00000) {
+ if (iy == 0x7ff00000) {
+ switch (m) {
+ case 0:
+ return PI_O_4 + TINY;/* ieee_atan(+INF,+INF) */
+ case 1:
+ return -PI_O_4 - TINY;/* ieee_atan(-INF,+INF) */
+ case 2:
+ return 3.0 * PI_O_4 + TINY;/* ieee_atan(+INF,-INF) */
+ case 3:
+ return -3.0 * PI_O_4 - TINY;/* ieee_atan(-INF,-INF) */
+ }
+ } else {
+ switch (m) {
+ case 0:
+ return 0.0; /* ieee_atan(+...,+INF) */
+ case 1:
+ return -0.0; /* ieee_atan(-...,+INF) */
+ case 2:
+ return 3.14159265358979311600e+00 + TINY; /* ieee_atan(+...,-INF) */
+ case 3:
+ return -3.14159265358979311600e+00 - TINY; /* ieee_atan(-...,-INF) */
+ }
+ }
+ }
+ /* when y is INF */
+ if (iy == 0x7ff00000)
+ return (hy < 0) ? -PI_O_2 - TINY : PI_O_2 + TINY;
+
+ /* compute y/x */
+ k = (iy - ix) >> 20;
+ if (k > 60) {
+ z = PI_O_2 + 0.5 * PI_LO; /* |y/x| > 2**60 */
+ } else if (hx < 0 && k < -60) {
+ z = 0.0; /* |y|/x < -2**60 */
+ } else {
+ z = StrictMath.atan(Math.abs(y / x)); /* safe to do y/x */
+ }
+
+ switch (m) {
+ case 0:
+ return z; /* ieee_atan(+,+) */
+ case 1:
+ // __HI(z) ^= 0x80000000;
+ z = Double.longBitsToDouble(
+ Double.doubleToRawLongBits(z) ^ (0x80000000L << 32));
+ return z; /* ieee_atan(-,+) */
+ case 2:
+ return 3.14159265358979311600e+00 - (z - PI_LO);/* ieee_atan(+,-) */
+ default: /* case 3 */
+ return (z - PI_LO) - 3.14159265358979311600e+00;/* ieee_atan(-,-) */
+ }
+ }
+
+ private static final int B1 = 715094163;
+ private static final int B2 = 696219795;
+ private static final double C = 5.42857142857142815906e-01;
+ private static final double D = -7.05306122448979611050e-01;
+ private static final double CBRTE = 1.41428571428571436819e+00;
+ private static final double F = 1.60714285714285720630e+00;
+ private static final double G = 3.57142857142857150787e-01;
/**
* Returns the closest double approximation of the cube root of the
@@ -207,11 +512,79 @@ public final class StrictMath {
* <li>{@code cbrt(NaN) = NaN}</li>
* </ul>
*
- * @param d
+ * @param x
* the value whose cube root has to be computed.
* @return the cube root of the argument.
*/
- public static native double cbrt(double d);
+ public static double cbrt(double x) {
+ if (x < 0) {
+ return -cbrt(-x);
+ }
+ int hx;
+ double r, s, w;
+ int sign; // caution: should be unsigned
+ long bits = Double.doubleToRawLongBits(x);
+
+ hx = (int) (bits >>> 32);
+ sign = hx & 0x80000000; /* sign= sign(x) */
+ hx ^= sign;
+ if (hx >= 0x7ff00000) {
+ return (x + x); /* ieee_cbrt(NaN,INF) is itself */
+ }
+
+ if ((hx | ((int) bits)) == 0) {
+ return x; /* ieee_cbrt(0) is itself */
+ }
+
+ // __HI(x) = hx; /* x <- |x| */
+ bits &= 0x00000000ffffffffL;
+ bits |= ((long) hx << 32);
+
+ long tBits = Double.doubleToRawLongBits(0.0) & 0x00000000ffffffffL;
+ double t = 0.0;
+ /* rough cbrt to 5 bits */
+ if (hx < 0x00100000) { /* subnormal number */
+ // __HI(t)=0x43500000; /*set t= 2**54*/
+ tBits |= 0x43500000L << 32;
+ t = Double.longBitsToDouble(tBits);
+ t *= x;
+
+ // __HI(t)=__HI(t)/3+B2;
+ tBits = Double.doubleToRawLongBits(t);
+ long tBitsHigh = tBits >> 32;
+ tBits &= 0x00000000ffffffffL;
+ tBits |= ((tBitsHigh / 3) + B2) << 32;
+ t = Double.longBitsToDouble(tBits);
+
+ } else {
+ // __HI(t)=hx/3+B1;
+ tBits |= ((long) ((hx / 3) + B1)) << 32;
+ t = Double.longBitsToDouble(tBits);
+ }
+
+ /* new cbrt to 23 bits, may be implemented in single precision */
+ r = t * t / x;
+ s = C + r * t;
+ t *= G + F / (s + CBRTE + D / s);
+
+ /* chopped to 20 bits and make it larger than ieee_cbrt(x) */
+ tBits = Double.doubleToRawLongBits(t);
+ tBits &= 0xFFFFFFFFL << 32;
+ tBits += 0x00000001L << 32;
+ t = Double.longBitsToDouble(tBits);
+
+ /* one step newton iteration to 53 bits with error less than 0.667 ulps */
+ s = t * t; /* t*t is exact */
+ r = x / s;
+ w = t + t;
+ r = (r - t) / (w + r); /* r-s is exact */
+ t = t + t * r;
+
+ /* retore the sign bit */
+ tBits = Double.doubleToRawLongBits(t);
+ tBits |= ((long) sign) << 32;
+ return Double.longBitsToDouble(tBits);
+ }
/**
* Returns the double conversion of the most negative (closest to negative
@@ -229,6 +602,8 @@ public final class StrictMath {
*/
public static native double ceil(double d);
+ private static final long ONEBITS = Double.doubleToRawLongBits(1.00000000000000000000e+00)
+ & 0x00000000ffffffffL;
/**
* Returns the closest double approximation of the hyperbolic cosine of the
@@ -241,11 +616,54 @@ public final class StrictMath {
* <li>{@code cosh(NaN) = NaN}</li>
* </ul>
*
- * @param d
+ * @param x
* the value whose hyperbolic cosine has to be computed.
* @return the hyperbolic cosine of the argument.
*/
- public static native double cosh(double d);
+ public static double cosh(double x) {
+ double t, w;
+ int ix;
+ final long bits = Double.doubleToRawLongBits(x);
+ ix = (int) (bits >>> 32) & 0x7fffffff;
+
+ /* x is INF or NaN */
+ if (ix >= 0x7ff00000) {
+ return x * x;
+ }
+
+ /* |x| in [0,0.5*ln2], return 1+ieee_expm1(|x|)^2/(2*ieee_exp(|x|)) */
+ if (ix < 0x3fd62e43) {
+ t = expm1(Math.abs(x));
+ w = 1.00000000000000000000e+00 + t;
+ if (ix < 0x3c800000)
+ return w; /* ieee_cosh(tiny) = 1 */
+ return 1.00000000000000000000e+00 + (t * t) / (w + w);
+ }
+
+ /* |x| in [0.5*ln2,22], return (ieee_exp(|x|)+1/ieee_exp(|x|)/2; */
+ if (ix < 0x40360000) {
+ t = exp(Math.abs(x));
+ return 0.5 * t + 0.5 / t;
+ }
+
+ /* |x| in [22, ieee_log(maxdouble)] return half*ieee_exp(|x|) */
+ if (ix < 0x40862E42) {
+ return 0.5 * exp(Math.abs(x));
+ }
+
+ /* |x| in [log(maxdouble), overflowthresold] */
+ final long lx = ((ONEBITS >>> 29) + ((int) bits)) & 0x00000000ffffffffL;
+ // watch out: lx should be an unsigned int
+ // lx = *( (((*(unsigned*)&one)>>29)) + (unsigned*)&x);
+ if (ix < 0x408633CE || (ix == 0x408633ce) && (lx <= 0x8fb9f87dL)) {
+ w = exp(0.5 * Math.abs(x));
+ t = 0.5 * w;
+ return t * w;
+ }
+
+ /* |x| > overflowthresold, ieee_cosh(x) overflow */
+ return HUGE * HUGE;
+ }
/**
* Returns the closest double approximation of the cosine of the argument.
@@ -263,6 +681,19 @@ public final class StrictMath {
*/
public static native double cos(double d);
+ private static final double TWON24 = 5.96046447753906250000e-08;
+ private static final double TWO54 = 1.80143985094819840000e+16,
+ TWOM54 = 5.55111512312578270212e-17;
+ private static final double TWOM1000 = 9.33263618503218878990e-302;
+ private static final double O_THRESHOLD = 7.09782712893383973096e+02;
+ private static final double U_THRESHOLD = -7.45133219101941108420e+02;
+ private static final double INVLN2 = 1.44269504088896338700e+00;
+ private static final double P1 = 1.66666666666666019037e-01;
+ private static final double P2 = -2.77777777770155933842e-03;
+ private static final double P3 = 6.61375632143793436117e-05;
+ private static final double P4 = -1.65339022054652515390e-06;
+ private static final double P5 = 4.13813679705723846039e-08;
+
/**
* Returns the closest double approximation of the raising "e" to the power
* of the argument.
@@ -274,11 +705,88 @@ public final class StrictMath {
* <li>{@code exp(NaN) = NaN}</li>
* </ul>
*
- * @param d
+ * @param x
* the value whose exponential has to be computed.
* @return the exponential of the argument.
*/
- public static native double exp(double d);
+ public static double exp(double x) {
+ double y, c, t;
+ double hi = 0, lo = 0;
+ int k = 0, xsb;
+ int hx; // should be unsigned, be careful!
+ final long bits = Double.doubleToRawLongBits(x);
+ int lowBits = (int) bits;
+ int highBits = (int) (bits >>> 32);
+ hx = highBits & 0x7fffffff;
+ xsb = (highBits >>> 31) & 1;
+
+ /* filter out non-finite argument */
+ if (hx >= 0x40862E42) { /* if |x|>=709.78... */
+ if (hx >= 0x7ff00000) {
+ if (((hx & 0xfffff) | lowBits) != 0) {
+ return x + x; /* NaN */
+ } else {
+ return (xsb == 0) ? x : 0.0; /* ieee_exp(+-inf)={inf,0} */
+ }
+ }
+
+ if (x > O_THRESHOLD) {
+ return HUGE * HUGE; /* overflow */
+ }
+
+ if (x < U_THRESHOLD) {
+ return TWOM1000 * TWOM1000; /* underflow */
+ }
+ }
+
+ /* argument reduction */
+ if (hx > 0x3fd62e42) { /* if |x| > 0.5 ln2 */
+ if (hx < 0x3FF0A2B2) { /* and |x| < 1.5 ln2 */
+ hi = x - ((xsb == 0) ? 6.93147180369123816490e-01 :
+ -6.93147180369123816490e-01); // LN2HI[xsb];
+ lo = (xsb == 0) ? 1.90821492927058770002e-10 :
+ -1.90821492927058770002e-10; // LN2LO[xsb];
+ k = 1 - xsb - xsb;
+ } else {
+ k = (int) (INVLN2 * x + ((xsb == 0) ? 0.5 : -0.5 ));//halF[xsb]);
+ t = k;
+ hi = x - t * 6.93147180369123816490e-01; //ln2HI[0]; /* t*ln2HI is exact here */
+ lo = t * 1.90821492927058770002e-10; //ln2LO[0];
+ }
+ x = hi - lo;
+ } else if (hx < 0x3e300000) { /* when |x|<2**-28 */
+ if (HUGE + x > 1.00000000000000000000e+00)
+ return 1.00000000000000000000e+00 + x;/* trigger inexact */
+ } else {
+ k = 0;
+ }
+
+ /* x is now in primary range */
+ t = x * x;
+ c = x - t * (P1 + t * (P2 + t * (P3 + t * (P4 + t * P5))));
+ if (k == 0) {
+ return 1.00000000000000000000e+00 - ((x * c) / (c - 2.0) - x);
+ } else {
+ y = 1.00000000000000000000e+00 - ((lo - (x * c) / (2.0 - c)) - hi);
+ }
+ long yBits = Double.doubleToRawLongBits(y);
+ if (k >= -1021) {
+ yBits += ((long) (k << 20)) << 32; /* add k to y's exponent */
+ return Double.longBitsToDouble(yBits);
+ } else {
+ yBits += ((long) ((k + 1000) << 20)) << 32;/* add k to y's exponent */
+ return Double.longBitsToDouble(yBits) * TWOM1000;
+ }
+ }
+
+ private static final double TINY = 1.0e-300;
+ private static final double LN2_HI = 6.93147180369123816490e-01;
+ private static final double LN2_LO = 1.90821492927058770002e-10;
+ private static final double Q1 = -3.33333333333331316428e-02;
+ private static final double Q2 = 1.58730158725481460165e-03;
+ private static final double Q3 = -7.93650757867487942473e-05;
+ private static final double Q4 = 4.00821782732936239552e-06;
+ private static final double Q5 = -2.01099218183624371326e-07;
/**
* Returns the closest double approximation of <i>{@code e}</i><sup>
@@ -295,17 +803,124 @@ public final class StrictMath {
* <li>{@code expm1(NaN) = NaN}</li>
* </ul>
*
- * @param d
+ * @param x
* the value to compute the <i>{@code e}</i><sup>{@code d}</sup>
* {@code - 1} of.
- * @return the <i>{@code e}</i><sup>{@code d}</sup>{@code - 1} value
- * of the argument.
+ * @return the <i>{@code e}</i><sup>{@code d}</sup>{@code - 1} value of the
+ * argument.
*/
- public static native double expm1(double d);
+ public static double expm1(double x) {
+ double y, hi, lo, t, e, hxs, hfx, r1, c = 0.0;
+ int k, xsb;
+ long yBits = 0;
+ final long bits = Double.doubleToRawLongBits(x);
+ int highBits = (int) (bits >>> 32);
+ int lowBits = (int) (bits);
+ int hx = highBits & 0x7fffffff; // caution: should be unsigned!
+ xsb = highBits & 0x80000000; /* sign bit of x */
+ y = xsb == 0 ? x : -x; /* y = |x| */
+
+ /* filter out huge and non-finite argument */
+ if (hx >= 0x4043687A) { /* if |x|>=56*ln2 */
+ if (hx >= 0x40862E42) { /* if |x|>=709.78... */
+ if (hx >= 0x7ff00000) {
+ if (((hx & 0xfffff) | lowBits) != 0) {
+ return x + x; /* NaN */
+ } else {
+ return (xsb == 0) ? x : -1.0;/* ieee_exp(+-inf)={inf,-1} */
+ }
+ }
+ if (x > O_THRESHOLD) {
+ return HUGE * HUGE; /* overflow */
+ }
+ }
+ if (xsb != 0) { /* x < -56*ln2, return -1.0 with inexact */
+ if (x + TINY < 0.0) { /* raise inexact */
+ return TINY - 1.00000000000000000000e+00; /* return -1 */
+ }
+ }
+ }
+ /* argument reduction */
+ if (hx > 0x3fd62e42) { /* if |x| > 0.5 ln2 */
+ if (hx < 0x3FF0A2B2) { /* and |x| < 1.5 ln2 */
+ if (xsb == 0) {
+ hi = x - LN2_HI;
+ lo = LN2_LO;
+ k = 1;
+ } else {
+ hi = x + LN2_HI;
+ lo = -LN2_LO;
+ k = -1;
+ }
+ } else {
+ k = (int) (INVLN2 * x + ((xsb == 0) ? 0.5 : -0.5));
+ t = k;
+ hi = x - t * LN2_HI; /* t*ln2_hi is exact here */
+ lo = t * LN2_LO;
+ }
+ x = hi - lo;
+ c = (hi - x) - lo;
+ } else if (hx < 0x3c900000) { /* when |x|<2**-54, return x */
+ // t = huge+x; /* return x with inexact flags when x!=0 */
+ // return x - (t-(huge+x));
+ return x; // inexact flag is not set, but Java ignors this flag
+ // anyway
+ } else {
+ k = 0;
+ }
+
+ /* x is now in primary range */
+ hfx = 0.5 * x;
+ hxs = x * hfx;
+ r1 = 1.00000000000000000000e+00 + hxs * (Q1 + hxs * (Q2 + hxs * (Q3 + hxs * (Q4 + hxs * Q5))));
+ t = 3.0 - r1 * hfx;
+ e = hxs * ((r1 - t) / (6.0 - x * t));
+ if (k == 0) {
+ return x - (x * e - hxs); /* c is 0 */
+ } else {
+ e = (x * (e - c) - c);
+ e -= hxs;
+ if (k == -1) {
+ return 0.5 * (x - e) - 0.5;
+ }
+
+ if (k == 1) {
+ if (x < -0.25) {
+ return -2.0 * (e - (x + 0.5));
+ } else {
+ return 1.00000000000000000000e+00 + 2.0 * (x - e);
+ }
+ }
+
+ if (k <= -2 || k > 56) { /* suffice to return ieee_exp(x)-1 */
+ y = 1.00000000000000000000e+00 - (e - x);
+ yBits = Double.doubleToRawLongBits(y);
+ yBits += (((long) k) << 52); /* add k to y's exponent */
+ return Double.longBitsToDouble(yBits) - 1.00000000000000000000e+00;
+ }
+
+ long tBits = Double.doubleToRawLongBits(1.00000000000000000000e+00) & 0x00000000ffffffffL;
+
+ if (k < 20) {
+ tBits |= (((long) 0x3ff00000) - (0x200000 >> k)) << 32;
+ y = Double.longBitsToDouble(tBits) - (e - x);
+ yBits = Double.doubleToRawLongBits(y);
+ yBits += (((long) k) << 52); /* add k to y's exponent */
+ return Double.longBitsToDouble(yBits);
+ } else {
+ tBits |= ((((long) 0x3ff) - k) << 52); /* 2^-k */
+ y = x - (e + Double.longBitsToDouble(tBits));
+ y += 1.00000000000000000000e+00;
+ yBits = Double.doubleToRawLongBits(y);
+ yBits += (((long) k) << 52); /* add k to y's exponent */
+ return Double.longBitsToDouble(yBits);
+ }
+ }
+ }
/**
- * Returns the double conversion of the most positive (closest to
- * positive infinity) integer less than or equal to the argument.
+ * Returns the double conversion of the most positive (closest to positive
+ * infinity) integer less than or equal to the argument.
* <p>
* Special cases:
* <ul>
@@ -319,9 +934,9 @@ public final class StrictMath {
public static native double floor(double d);
/**
- * Returns {@code sqrt(}<i>{@code x}</i><sup>{@code 2}</sup>{@code +}
- * <i> {@code y}</i><sup>{@code 2}</sup>{@code )}. The final result is
- * without medium underflow or overflow.
+ * Returns {@code sqrt(}<i>{@code x}</i><sup>{@code 2}</sup>{@code +} <i>
+ * {@code y}</i><sup>{@code 2}</sup>{@code )}. The final result is without
+ * medium underflow or overflow.
* <p>
* Special cases:
* <ul>
@@ -369,6 +984,14 @@ public final class StrictMath {
*/
public static native double IEEEremainder(double x, double y);
+ private static final double LG1 = 6.666666666666735130e-01;
+ private static final double LG2 = 3.999999999940941908e-01;
+ private static final double LG3 = 2.857142874366239149e-01;
+ private static final double LG4 = 2.222219843214978396e-01;
+ private static final double LG5 = 1.818357216161805012e-01;
+ private static final double LG6 = 1.531383769920937332e-01;
+ private static final double LG7 = 1.479819860511658591e-01;
+
/**
* Returns the closest double approximation of the natural logarithm of the
* argument.
@@ -383,11 +1006,95 @@ public final class StrictMath {
* <li>{@code log(NaN) = NaN}</li>
* </ul>
*
- * @param d
+ * @param x
* the value whose log has to be computed.
* @return the natural logarithm of the argument.
*/
- public static native double log(double d);
+ public static double log(double x) {
+ double hfsq, f, s, z, R, w, t1, t2, dk;
+ int hx, i, j, k = 0;
+ int lx; // watch out, should be unsigned
+
+ long bits = Double.doubleToRawLongBits(x);
+ hx = (int) (bits >>> 32); /* high word of x */
+ lx = (int) bits; /* low word of x */
+
+ if (hx < 0x00100000) { /* x < 2**-1022 */
+ if (((hx & 0x7fffffff) | lx) == 0) {
+ return -TWO54 / 0.0; /* ieee_log(+-0)=-inf */
+ }
+
+ if (hx < 0) {
+ return (x - x) / 0.0; /* ieee_log(-#) = NaN */
+ }
+
+ k -= 54;
+ x *= TWO54; /* subnormal number, scale up x */
+ bits = Double.doubleToRawLongBits(x);
+ hx = (int) (bits >>> 32); /* high word of x */
+ }
+
+ if (hx >= 0x7ff00000) {
+ return x + x;
+ }
+
+ k += (hx >> 20) - 1023;
+ hx &= 0x000fffff;
+ bits &= 0x00000000ffffffffL;
+ i = (hx + 0x95f64) & 0x100000;
+ bits |= ((long) hx | (i ^ 0x3ff00000)) << 32; /* normalize x or x/2 */
+ x = Double.longBitsToDouble(bits);
+ k += (i >> 20);
+ f = x - 1.0;
+
+ if ((0x000fffff & (2 + hx)) < 3) { /* |f| < 2**-20 */
+ if (f == 0.0) {
+ if (k == 0) {
+ return 0.0;
+ } else {
+ dk = k;
+ }
+ return dk * LN2_HI + dk * LN2_LO;
+ }
+
+ R = f * f * (0.5 - 0.33333333333333333 * f);
+ if (k == 0) {
+ return f - R;
+ } else {
+ dk = k;
+ return dk * LN2_HI - ((R - dk * LN2_LO) - f);
+ }
+ }
+ s = f / (2.0 + f);
+ dk = k;
+ z = s * s;
+ i = hx - 0x6147a;
+ w = z * z;
+ j = 0x6b851 - hx;
+ t1 = w * (LG2 + w * (LG4 + w * LG6));
+ t2 = z * (LG1 + w * (LG3 + w * (LG5 + w * LG7)));
+ i |= j;
+ R = t2 + t1;
+ if (i > 0) {
+ hfsq = 0.5 * f * f;
+ if (k == 0) {
+ return f - (hfsq - s * (hfsq + R));
+ } else {
+ return dk * LN2_HI
+ - ((hfsq - (s * (hfsq + R) + dk * LN2_LO)) - f);
+ }
+ } else {
+ if (k == 0) {
+ return f - s * (f - R);
+ } else {
+ return dk * LN2_HI - ((s * (f - R) - dk * LN2_LO) - f);
+ }
+ }
+ }
+
+ private static final double IVLN10 = 4.34294481903251816668e-01;
+ private static final double LOG10_2HI = 3.01029995663611771306e-01;
+ private static final double LOG10_2LO = 3.69423907715893078616e-13;
/**
* Returns the closest double approximation of the base 10 logarithm of the
@@ -403,11 +1110,54 @@ public final class StrictMath {
* <li>{@code log10(NaN) = NaN}</li>
* </ul>
*
- * @param d
+ * @param x
* the value whose base 10 log has to be computed.
- * @return the natural logarithm of the argument.
+ * @return the the base 10 logarithm of x
*/
- public static native double log10(double d);
+ public static double log10(double x) {
+ double y, z;
+ int i, k = 0, hx;
+ int lx; // careful: lx should be unsigned!
+ long bits = Double.doubleToRawLongBits(x);
+ hx = (int) (bits >> 32); /* high word of x */
+ lx = (int) bits; /* low word of x */
+ if (hx < 0x00100000) { /* x < 2**-1022 */
+ if (((hx & 0x7fffffff) | lx) == 0) {
+ return -TWO54 / 0.0; /* ieee_log(+-0)=-inf */
+ }
+
+ if (hx < 0) {
+ return (x - x) / 0.0; /* ieee_log(-#) = NaN */
+ }
+
+ k -= 54;
+ x *= TWO54; /* subnormal number, scale up x */
+ bits = Double.doubleToRawLongBits(x);
+ hx = (int) (bits >> 32); /* high word of x */
+ }
+
+ if (hx >= 0x7ff00000) {
+ return x + x;
+ }
+
+ k += (hx >> 20) - 1023;
+ i = (int) (((k & 0x00000000ffffffffL) & 0x80000000) >>> 31);
+ hx = (hx & 0x000fffff) | ((0x3ff - i) << 20);
+ y = k + i;
+ bits &= 0x00000000ffffffffL;
+ bits |= ((long) hx) << 32;
+ x = Double.longBitsToDouble(bits); // __HI(x) = hx;
+ z = y * LOG10_2LO + IVLN10 * log(x);
+ return z + y * LOG10_2HI;
+ }
+
+ private static final double LP1 = 6.666666666666735130e-01,
+ LP2 = 3.999999999940941908e-01, /* 3FD99999 9997FA04 */
+ LP3 = 2.857142874366239149e-01, /* 3FD24924 94229359 */
+ LP4 = 2.222219843214978396e-01, /* 3FCC71C5 1D8E78AF */
+ LP5 = 1.818357216161805012e-01, /* 3FC74664 96CB03DE */
+ LP6 = 1.531383769920937332e-01, /* 3FC39A09 D078C69F */
+ LP7 = 1.479819860511658591e-01; /* 3FC2F112 DF3E5244 */
/**
* Returns the closest double approximation of the natural logarithm of the
@@ -426,11 +1176,107 @@ public final class StrictMath {
* <li>{@code log1p(NaN) = NaN}</li>
* </ul>
*
- * @param d
+ * @param x
* the value to compute the {@code ln(1+d)} of.
* @return the natural logarithm of the sum of the argument and 1.
*/
- public static native double log1p(double d);
+
+ public static double log1p(double x) {
+ double hfsq, f = 0.0, c = 0.0, s, z, R, u = 0.0;
+ int k, hx, hu = 0, ax;
+
+ final long bits = Double.doubleToRawLongBits(x);
+ hx = (int) (bits >>> 32); /* high word of x */
+ ax = hx & 0x7fffffff;
+
+ k = 1;
+ if (hx < 0x3FDA827A) { /* x < 0.41422 */
+ if (ax >= 0x3ff00000) { /* x <= -1.0 */
+ if (x == -1.0) {
+ return -TWO54 / 0.0; /* ieee_log1p(-1)=+inf */
+ } else {
+ return (x - x) / (x - x); /* ieee_log1p(x<-1)=NaN */
+ }
+ }
+ if (ax < 0x3e200000) {
+ if (TWO54 + x > 0.0 && ax < 0x3c900000) {
+ return x;
+ } else {
+ return x - x * x * 0.5;
+ }
+ }
+ if (hx > 0 || hx <= 0xbfd2bec3) {
+ k = 0;
+ f = x;
+ hu = 1;
+ } /* -0.2929<x<0.41422 */
+ }
+
+ if (hx >= 0x7ff00000) {
+ return x + x;
+ }
+
+ if (k != 0) {
+ long uBits;
+ if (hx < 0x43400000) {
+ u = 1.0 + x;
+ uBits = Double.doubleToRawLongBits(u);
+ hu = (int) (uBits >>> 32);
+ k = (hu >> 20) - 1023;
+ c = (k > 0) ? 1.0 - (u - x) : x - (u - 1.0);/* correction term */
+ c /= u;
+ } else {
+ uBits = Double.doubleToRawLongBits(x);
+ hu = (int) (uBits >>> 32);
+ k = (hu >> 20) - 1023;
+ c = 0;
+ }
+ hu &= 0x000fffff;
+ if (hu < 0x6a09e) {
+ // __HI(u) = hu|0x3ff00000; /* normalize u */
+ uBits &= 0x00000000ffffffffL;
+ uBits |= ((long) hu | 0x3ff00000) << 32;
+ u = Double.longBitsToDouble(uBits);
+ } else {
+ k += 1;
+ // __HI(u) = hu|0x3fe00000; /* normalize u/2 */
+ uBits &= 0xffffffffL;
+ uBits |= ((long) hu | 0x3fe00000) << 32;
+ u = Double.longBitsToDouble(uBits);
+ hu = (0x00100000 - hu) >> 2;
+ }
+ f = u - 1.0;
+ }
+ hfsq = 0.5 * f * f;
+ if (hu == 0) { /* |f| < 2**-20 */
+ if (f == 0.0) {
+ if (k == 0) {
+ return 0.0;
+ } else {
+ c += k * LN2_LO;
+ return k * LN2_HI + c;
+ }
+ }
+
+ R = hfsq * (1.0 - 0.66666666666666666 * f);
+ if (k == 0) {
+ return f - R;
+ } else {
+ return k * LN2_HI - ((R - (k * LN2_LO + c)) - f);
+ }
+ }
+
+ s = f / (2.0 + f);
+ z = s * s;
+ R = z * (LP1 + z * (LP2 + z
+ * (LP3 + z * (LP4 + z * (LP5 + z * (LP6 + z * LP7))))));
+ if (k == 0) {
+ return f - (hfsq - s * (hfsq + R));
+ } else {
+ return k * LN2_HI
+ - ((hfsq - (s * (hfsq + R) + (k * LN2_LO + c))) - f);
+ }
+ }
/**
* Returns the most positive (closest to positive infinity) of the two
@@ -453,8 +1299,8 @@ public final class StrictMath {
if (d1 != d2)
return Double.NaN;
/* max( +0.0,-0.0) == +0.0 */
- if (d1 == 0.0
- && ((Double.doubleToLongBits(d1) & Double.doubleToLongBits(d2)) & 0x8000000000000000L) == 0)
+ if (d1 == 0.0 &&
+ ((Double.doubleToLongBits(d1) & Double.doubleToLongBits(d2)) & 0x8000000000000000L) == 0)
return 0.0;
return d1;
}
@@ -480,8 +1326,8 @@ public final class StrictMath {
if (f1 != f2)
return Float.NaN;
/* max( +0.0,-0.0) == +0.0 */
- if (f1 == 0.0f
- && ((Float.floatToIntBits(f1) & Float.floatToIntBits(f2)) & 0x80000000) == 0)
+ if (f1 == 0.0f &&
+ ((Float.floatToIntBits(f1) & Float.floatToIntBits(f2)) & 0x80000000) == 0)
return 0.0f;
return f1;
}
@@ -523,8 +1369,8 @@ public final class StrictMath {
if (d1 != d2)
return Double.NaN;
/* min( +0.0,-0.0) == -0.0 */
- if (d1 == 0.0
- && ((Double.doubleToLongBits(d1) | Double.doubleToLongBits(d2)) & 0x8000000000000000l) != 0)
+ if (d1 == 0.0 &&
+ ((Double.doubleToLongBits(d1) | Double.doubleToLongBits(d2)) & 0x8000000000000000l) != 0)
return 0.0 * (-1.0);
return d1;
}
@@ -550,8 +1396,8 @@ public final class StrictMath {
if (f1 != f2)
return Float.NaN;
/* min( +0.0,-0.0) == -0.0 */
- if (f1 == 0.0f
- && ((Float.floatToIntBits(f1) | Float.floatToIntBits(f2)) & 0x80000000) != 0)
+ if (f1 == 0.0f &&
+ ((Float.floatToIntBits(f1) | Float.floatToIntBits(f2)) & 0x80000000) != 0)
return 0.0f * (-1.0f);
return f1;
}
@@ -706,7 +1552,7 @@ public final class StrictMath {
* the value whose signum has to be computed.
* @return the value of the signum function.
*/
- public static double signum(double d){
+ public static double signum(double d) {
return Math.signum(d);
}
@@ -729,10 +1575,12 @@ public final class StrictMath {
* the value whose signum has to be computed.
* @return the value of the signum function.
*/
- public static float signum(float f){
+ public static float signum(float f) {
return Math.signum(f);
}
+ private static final double shuge = 1.0e307;
+
/**
* Returns the closest double approximation of the hyperbolic sine of the
* argument.
@@ -746,11 +1594,57 @@ public final class StrictMath {
* <li>{@code sinh(NaN) = NaN}</li>
* </ul>
*
- * @param d
+ * @param x
* the value whose hyperbolic sine has to be computed.
* @return the hyperbolic sine of the argument.
*/
- public static native double sinh(double d);
+ public static double sinh(double x) {
+ double t, w, h;
+ int ix, jx;
+ final long bits = Double.doubleToRawLongBits(x);
+
+ jx = (int) (bits >>> 32);
+ ix = jx & 0x7fffffff;
+
+ /* x is INF or NaN */
+ if (ix >= 0x7ff00000) {
+ return x + x;
+ }
+
+ h = 0.5;
+ if (jx < 0) {
+ h = -h;
+ }
+
+ /* |x| in [0,22], return sign(x)*0.5*(E+E/(E+1))) */
+ if (ix < 0x40360000) { /* |x|<22 */
+ if (ix < 0x3e300000) /* |x|<2**-28 */
+ if (shuge + x > 1.00000000000000000000e+00) {
+ return x;/* ieee_sinh(tiny) = tiny with inexact */
+ }
+ t = expm1(Math.abs(x));
+ if (ix < 0x3ff00000)
+ return h * (2.0 * t - t * t / (t + 1.00000000000000000000e+00));
+ return h * (t + t / (t + 1.00000000000000000000e+00));
+ }
+
+ /* |x| in [22, ieee_log(maxdouble)] return 0.5*ieee_exp(|x|) */
+ if (ix < 0x40862E42) {
+ return h * exp(Math.abs(x));
+ }
+
+ /* |x| in [log(maxdouble), overflowthresold] */
+ final long lx = ((ONEBITS >>> 29) + ((int) bits)) & 0x00000000ffffffffL;
+ // lx = *( (((*(unsigned*)&one)>>29)) + (unsigned*)&x);
+ if (ix < 0x408633CE || (ix == 0x408633ce) && (lx <= 0x8fb9f87dL)) {
+ w = exp(0.5 * Math.abs(x));
+ t = h * w;
+ return t * w;
+ }
+
+ /* |x| > overflowthresold, ieee_sinh(x) overflow */
+ return x * shuge;
+ }
/**
* Returns the closest double approximation of the sine of the argument.
@@ -816,11 +1710,47 @@ public final class StrictMath {
* <li>{@code tanh(NaN) = NaN}</li>
* </ul>
*
- * @param d
+ * @param x
* the value whose hyperbolic tangent has to be computed.
* @return the hyperbolic tangent of the argument
*/
- public static native double tanh(double d);
+ public static double tanh(double x) {
+ double t, z;
+ int jx, ix;
+
+ final long bits = Double.doubleToRawLongBits(x);
+ /* High word of |x|. */
+ jx = (int) (bits >>> 32);
+ ix = jx & 0x7fffffff;
+
+ /* x is INF or NaN */
+ if (ix >= 0x7ff00000) {
+ if (jx >= 0) {
+ return 1.00000000000000000000e+00 / x + 1.00000000000000000000e+00; /* ieee_tanh(+-inf)=+-1 */
+ } else {
+ return 1.00000000000000000000e+00 / x - 1.00000000000000000000e+00; /* ieee_tanh(NaN) = NaN */
+ }
+ }
+
+ /* |x| < 22 */
+ if (ix < 0x40360000) { /* |x|<22 */
+ if (ix < 0x3c800000) { /* |x|<2**-55 */
+ return x * (1.00000000000000000000e+00 + x);/* ieee_tanh(small) = small */
+ }
+
+ if (ix >= 0x3ff00000) { /* |x|>=1 */
+ t = Math.expm1(2.0 * Math.abs(x));
+ z = 1.00000000000000000000e+00 - 2.0 / (t + 2.0);
+ } else {
+ t = Math.expm1(-2.0 * Math.abs(x));
+ z = -t / (t + 2.0);
+ }
+ /* |x| > 22, return +-1 */
+ } else {
+ z = 1.00000000000000000000e+00 - TINY; /* raised inexact flag */
+ }
+ return (jx >= 0) ? z : -z;
+ }
/**
* Returns the measure in degrees of the supplied radian angle. The result
@@ -922,6 +1852,7 @@ public final class StrictMath {
/**
* Returns a double with the given magnitude and the sign of {@code sign}.
* If {@code sign} is NaN, the sign of the result is positive.
+ *
* @since 1.6
*/
public static double copySign(double magnitude, double sign) {
@@ -932,13 +1863,15 @@ public final class StrictMath {
// (Tested on a Nexus One.)
long magnitudeBits = Double.doubleToRawLongBits(magnitude);
long signBits = Double.doubleToRawLongBits((sign != sign) ? 1.0 : sign);
- magnitudeBits = (magnitudeBits & ~Double.SIGN_MASK) | (signBits & Double.SIGN_MASK);
+ magnitudeBits = (magnitudeBits & ~Double.SIGN_MASK)
+ | (signBits & Double.SIGN_MASK);
return Double.longBitsToDouble(magnitudeBits);
}
/**
- * Returns a float with the given magnitude and the sign of {@code sign}.
- * If {@code sign} is NaN, the sign of the result is positive.
+ * Returns a float with the given magnitude and the sign of {@code sign}. If
+ * {@code sign} is NaN, the sign of the result is positive.
+ *
* @since 1.6
*/
public static float copySign(float magnitude, float sign) {
@@ -949,12 +1882,14 @@ public final class StrictMath {
// (Tested on a Nexus One.)
int magnitudeBits = Float.floatToRawIntBits(magnitude);
int signBits = Float.floatToRawIntBits((sign != sign) ? 1.0f : sign);
- magnitudeBits = (magnitudeBits & ~Float.SIGN_MASK) | (signBits & Float.SIGN_MASK);
+ magnitudeBits = (magnitudeBits & ~Float.SIGN_MASK)
+ | (signBits & Float.SIGN_MASK);
return Float.intBitsToFloat(magnitudeBits);
}
/**
* Returns the exponent of float {@code f}.
+ *
* @since 1.6
*/
public static int getExponent(float f) {
@@ -963,14 +1898,17 @@ public final class StrictMath {
/**
* Returns the exponent of double {@code d}.
+ *
* @since 1.6
*/
- public static int getExponent(double d){
+ public static int getExponent(double d) {
return Math.getExponent(d);
}
/**
- * Returns the next double after {@code start} in the given {@code direction}.
+ * Returns the next double after {@code start} in the given
+ * {@code direction}.
+ *
* @since 1.6
*/
public static double nextAfter(double start, double direction) {
@@ -981,7 +1919,9 @@ public final class StrictMath {
}
/**
- * Returns the next float after {@code start} in the given {@code direction}.
+ * Returns the next float after {@code start} in the given {@code direction}
+ * .
+ *
* @since 1.6
*/
public static float nextAfter(float start, double direction) {
@@ -990,6 +1930,7 @@ public final class StrictMath {
/**
* Returns the next double larger than {@code d}.
+ *
* @since 1.6
*/
public static double nextUp(double d) {
@@ -998,6 +1939,7 @@ public final class StrictMath {
/**
* Returns the next float larger than {@code f}.
+ *
* @since 1.6
*/
public static float nextUp(float f) {
@@ -1006,6 +1948,7 @@ public final class StrictMath {
/**
* Returns {@code d} * 2^{@code scaleFactor}. The result may be rounded.
+ *
* @since 1.6
*/
public static double scalb(double d, int scaleFactor) {
@@ -1049,12 +1992,10 @@ public final class StrictMath {
} else {
if (Math.abs(d) >= Double.MIN_NORMAL) {
// common situation
- result = ((factor + Double.EXPONENT_BIAS) << Double.MANTISSA_BITS)
- | (bits & Double.MANTISSA_MASK);
+ result = ((factor + Double.EXPONENT_BIAS) << Double.MANTISSA_BITS) | (bits & Double.MANTISSA_MASK);
} else {
// origin d is sub-normal, change mantissa to normal style
- result = ((factor + Double.EXPONENT_BIAS) << Double.MANTISSA_BITS)
- | ((bits << (subNormalFactor + 1)) & Double.MANTISSA_MASK);
+ result = ((factor + Double.EXPONENT_BIAS) << Double.MANTISSA_BITS) | ((bits << (subNormalFactor + 1)) & Double.MANTISSA_MASK);
}
}
return Double.longBitsToDouble(result | sign);
@@ -1062,6 +2003,7 @@ public final class StrictMath {
/**
* Returns {@code d} * 2^{@code scaleFactor}. The result may be rounded.
+ *
* @since 1.6
*/
public static float scalb(float d, int scaleFactor) {
@@ -1073,8 +2015,7 @@ public final class StrictMath {
int factor = ((bits & Float.EXPONENT_MASK) >> Float.MANTISSA_BITS)
- Float.EXPONENT_BIAS + scaleFactor;
// calculates the factor of sub-normal values
- int subNormalFactor = Integer.numberOfLeadingZeros(bits & ~Float.SIGN_MASK)
- - Float.EXPONENT_BITS;
+ int subNormalFactor = Integer.numberOfLeadingZeros(bits & ~Float.SIGN_MASK) - Float.EXPONENT_BITS;
if (subNormalFactor < 0) {
// not sub-normal values
subNormalFactor = 0;
@@ -1105,8 +2046,9 @@ public final class StrictMath {
| (bits & Float.MANTISSA_MASK);
} else {
// origin d is sub-normal, change mantissa to normal style
- result = ((factor + Float.EXPONENT_BIAS) << Float.MANTISSA_BITS)
- | ((bits << (subNormalFactor + 1)) & Float.MANTISSA_MASK);
+ result = ((factor + Float.EXPONENT_BIAS)
+ << Float.MANTISSA_BITS) | (
+ (bits << (subNormalFactor + 1)) & Float.MANTISSA_MASK);
}
}
return Float.intBitsToFloat(result | sign);
@@ -1120,10 +2062,10 @@ public final class StrictMath {
}
// change it to positive
int absDigits = -digits;
- if (Integer.numberOfLeadingZeros(bits & ~Float.SIGN_MASK) <= (32 - absDigits)) {
+ if (Integer.numberOfLeadingZeros(bits & ~Float.SIGN_MASK)
+ <= (32 - absDigits)) {
// some bits will remain after shifting, calculates its carry
- if ((((bits >> (absDigits - 1)) & 0x1) == 0)
- || Integer.numberOfTrailingZeros(bits) == (absDigits - 1)) {
+ if ((((bits >> (absDigits - 1)) & 0x1) == 0) || Integer.numberOfTrailingZeros(bits) == (absDigits - 1)) {
return bits >> absDigits;
}
return ((bits >> absDigits) + 1);
@@ -1139,10 +2081,10 @@ public final class StrictMath {
}
// change it to positive
long absDigits = -digits;
- if (Long.numberOfLeadingZeros(bits & ~Double.SIGN_MASK) <= (64 - absDigits)) {
+ if (Long.numberOfLeadingZeros(bits & ~Double.SIGN_MASK)
+ <= (64 - absDigits)) {
// some bits will remain after shifting, calculates its carry
- if ((((bits >> (absDigits - 1)) & 0x1) == 0)
- || Long.numberOfTrailingZeros(bits) == (absDigits - 1)) {
+ if ((((bits >> (absDigits - 1)) & 0x1) == 0) || Long.numberOfTrailingZeros(bits) == (absDigits - 1)) {
return bits >> absDigits;
}
return ((bits >> absDigits) + 1);
diff --git a/luni/src/main/java/java/lang/System.java b/luni/src/main/java/java/lang/System.java
index 9425894..c5d9a89 100644
--- a/luni/src/main/java/java/lang/System.java
+++ b/luni/src/main/java/java/lang/System.java
@@ -50,6 +50,7 @@ import java.nio.channels.spi.SelectorProvider;
import java.util.AbstractMap;
import java.util.Collections;
import java.util.HashMap;
+import java.util.Locale;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
@@ -81,7 +82,10 @@ public final class System {
*/
public static final PrintStream err;
- private static final String lineSeparator;
+ private static final String PATH_SEPARATOR = ":";
+ private static final String LINE_SEPARATOR = "\n";
+ private static final String FILE_SEPARATOR = "/";
+
private static final Properties unchangeableSystemProperties;
private static Properties systemProperties;
@@ -107,7 +111,33 @@ public final class System {
in = new BufferedInputStream(new FileInputStream(FileDescriptor.in));
unchangeableSystemProperties = initUnchangeableSystemProperties();
systemProperties = createSystemProperties();
- lineSeparator = System.getProperty("line.separator");
+
+ addLegacyLocaleSystemProperties();
+ }
+
+ private static void addLegacyLocaleSystemProperties() {
+ final String locale = getProperty("user.locale", "");
+ if (!locale.isEmpty()) {
+ Locale l = Locale.forLanguageTag(locale);
+ setUnchangeableSystemProperty("user.language", l.getLanguage());
+ setUnchangeableSystemProperty("user.region", l.getCountry());
+ setUnchangeableSystemProperty("user.variant", l.getVariant());
+ } else {
+ // If "user.locale" isn't set we fall back to our old defaults of
+ // language="en" and region="US" (if unset) and don't attempt to set it.
+ // The Locale class will fall back to using user.language and
+ // user.region if unset.
+ final String language = getProperty("user.language", "");
+ final String region = getProperty("user.region", "");
+
+ if (language.isEmpty()) {
+ setUnchangeableSystemProperty("user.language", "en");
+ }
+
+ if (region.isEmpty()) {
+ setUnchangeableSystemProperty("user.region", "US");
+ }
+ }
}
/**
@@ -742,17 +772,11 @@ public final class System {
p.put("java.vm.vendor", projectName);
p.put("java.vm.version", runtime.vmVersion());
- p.put("file.separator", "/");
- p.put("line.separator", "\n");
- p.put("path.separator", ":");
-
p.put("java.runtime.name", "Android Runtime");
p.put("java.runtime.version", "0.9");
p.put("java.vm.vendor.url", projectUrl);
p.put("file.encoding", "UTF-8");
- p.put("user.language", "en");
- p.put("user.region", "US");
try {
StructPasswd passwd = Libcore.os.getpwuid(Libcore.os.getuid());
@@ -771,18 +795,48 @@ public final class System {
p.put("android.icu.unicode.version", ICU.getUnicodeVersion());
p.put("android.icu.cldr.version", ICU.getCldrVersion());
+ // Property override for ICU4J : this is the location of the ICU4C data. This
+ // is prioritized over the properties in ICUConfig.properties. The issue with using
+ // that is that it doesn't play well with jarjar and it needs complicated build rules
+ // to change its default value.
+ String icuDataPath = generateIcuDataPath();
+ p.put("android.icu.impl.ICUBinary.dataPath", icuDataPath);
+
parsePropertyAssignments(p, specialProperties());
// Override built-in properties with settings from the command line.
parsePropertyAssignments(p, runtime.properties());
+
+ if (p.containsKey("file.separator")) {
+ logE("Ignoring command line argument: -Dfile.separator");
+ }
+
+ if (p.containsKey("line.separator")) {
+ logE("Ignoring command line argument: -Dline.separator");
+ }
+
+ if (p.containsKey("path.separator")) {
+ logE("Ignoring command line argument: -Dpath.separator");
+ }
+
+ // We ignore values for "file.separator", "line.separator" and "path.separator" from
+ // the command line. They're fixed on the operating systems we support.
+ p.put("file.separator", FILE_SEPARATOR);
+ p.put("line.separator", LINE_SEPARATOR);
+ p.put("path.separator", PATH_SEPARATOR);
+
return p;
}
/**
* Inits an unchangeable system property with the given value.
- * This is useful when the environment needs to change under native bridge emulation.
+ *
+ * This is called from native code when the environment needs to change under native
+ * bridge emulation.
+ *
+ * @hide also visible for tests.
*/
- private static void initUnchangeableSystemProperty(String name, String value) {
+ public static void setUnchangeableSystemProperty(String name, String value) {
checkPropertyName(name);
unchangeableSystemProperties.put(name, value);
}
@@ -807,6 +861,37 @@ public final class System {
return p;
}
+ private static String generateIcuDataPath() {
+ StringBuilder icuDataPathBuilder = new StringBuilder();
+ // ICU should first look in ANDROID_DATA. This is used for (optional) timezone data.
+ String dataIcuDataPath = getEnvironmentPath("ANDROID_DATA", "/misc/zoneinfo/current/icu");
+ if (dataIcuDataPath != null) {
+ icuDataPathBuilder.append(dataIcuDataPath);
+ }
+
+ // ICU should always look in ANDROID_ROOT.
+ String systemIcuDataPath = getEnvironmentPath("ANDROID_ROOT", "/usr/icu");
+ if (systemIcuDataPath != null) {
+ if (icuDataPathBuilder.length() > 0) {
+ icuDataPathBuilder.append(":");
+ }
+ icuDataPathBuilder.append(systemIcuDataPath);
+ }
+ return icuDataPathBuilder.toString();
+ }
+
+ /**
+ * Creates a path by combining the value of an environment variable with a relative path.
+ * Returns {@code null} if the environment variable is not set.
+ */
+ private static String getEnvironmentPath(String environmentVariable, String path) {
+ String variable = getenv(environmentVariable);
+ if (variable == null) {
+ return null;
+ }
+ return variable + path;
+ }
+
/**
* Returns an array of "key=value" strings containing information not otherwise
* easily available, such as #defined library versions.
@@ -964,14 +1049,17 @@ public final class System {
public static native int identityHashCode(Object anObject);
/**
- * Returns the system's line separator. On Android, this is {@code "\n"}. The value
- * comes from the value of the {@code line.separator} system property when the VM
- * starts. Later changes to the property will not affect the value returned by this
- * method.
+ * Returns the system's line separator. On Android, this is {@code "\n"}. The value comes from
+ * the value of the {@code line.separator} system property.
+ *
+ * <p>On Android versions before Lollipop the {@code line.separator} system property can be
+ * modified but this method continues to return the original value. The system property cannot
+ * be modified on later versions of Android.
+ *
* @since 1.7
*/
public static String lineSeparator() {
- return lineSeparator;
+ return LINE_SEPARATOR;
}
/**
@@ -1106,7 +1194,12 @@ public final class System {
* named by the argument. On Android, this would turn {@code "MyLibrary"} into
* {@code "libMyLibrary.so"}.
*/
- public static native String mapLibraryName(String nickname);
+ public static String mapLibraryName(String nickname) {
+ if (nickname == null) {
+ throw new NullPointerException("nickname == null");
+ }
+ return "lib" + nickname + ".so";
+ }
/**
* Used to set System.err, System.in, and System.out.
diff --git a/luni/src/main/java/java/lang/ref/FinalizerReference.java b/luni/src/main/java/java/lang/ref/FinalizerReference.java
index 5416a80..02cfa01 100644
--- a/luni/src/main/java/java/lang/ref/FinalizerReference.java
+++ b/luni/src/main/java/java/lang/ref/FinalizerReference.java
@@ -82,7 +82,7 @@ public final class FinalizerReference<T> extends Reference<T> {
/**
* Waits for all currently-enqueued references to be finalized.
*/
- public static void finalizeAllEnqueued() throws InterruptedException {
+ public static void finalizeAllEnqueued(long timeout) throws InterruptedException {
// Alloate a new sentinel, this creates a FinalizerReference.
Sentinel sentinel;
// Keep looping until we safely enqueue our sentinel FinalizerReference.
@@ -91,7 +91,7 @@ public final class FinalizerReference<T> extends Reference<T> {
do {
sentinel = new Sentinel();
} while (!enqueueSentinelReference(sentinel));
- sentinel.awaitFinalization();
+ sentinel.awaitFinalization(timeout);
}
private static boolean enqueueSentinelReference(Sentinel sentinel) {
@@ -144,9 +144,22 @@ public final class FinalizerReference<T> extends Reference<T> {
notifyAll();
}
- synchronized void awaitFinalization() throws InterruptedException {
+ synchronized void awaitFinalization(long timeout) throws InterruptedException {
+ final long startTime = System.nanoTime();
+ final long endTime = startTime + timeout;
while (!finalized) {
- wait();
+ // 0 signifies no timeout.
+ if (timeout != 0) {
+ final long currentTime = System.nanoTime();
+ if (currentTime >= endTime) {
+ break;
+ } else {
+ final long deltaTime = endTime - currentTime;
+ wait(deltaTime / 1000000, (int)(deltaTime % 1000000));
+ }
+ } else {
+ wait();
+ }
}
}
}
diff --git a/luni/src/main/java/java/lang/reflect/Modifier.java b/luni/src/main/java/java/lang/reflect/Modifier.java
index 257064e..0480b8b 100644
--- a/luni/src/main/java/java/lang/reflect/Modifier.java
+++ b/luni/src/main/java/java/lang/reflect/Modifier.java
@@ -302,4 +302,23 @@ public class Modifier {
buf.setLength(buf.length() - 1);
return buf.toString();
}
+
+ /**
+ * Returns the modifiers for fields that can be present in a declaration.
+ * @hide
+ */
+ static String getDeclarationFieldModifiers(int modifiers) {
+ return Modifier.toString(modifiers & fieldModifiers());
+ }
+
+ /**
+ * Returns the modifiers for methods that can be present in a declaration.
+ * @hide
+ */
+ static String getDeclarationMethodModifiers(int modifiers) {
+ return Modifier.toString(modifiers & (
+ Modifier.isConstructor(modifiers)
+ ? Modifier.constructorModifiers()
+ : Modifier.methodModifiers()));
+ }
}
diff --git a/luni/src/main/java/java/net/DatagramSocket.java b/luni/src/main/java/java/net/DatagramSocket.java
index f9b72d8..3195240 100644
--- a/luni/src/main/java/java/net/DatagramSocket.java
+++ b/luni/src/main/java/java/net/DatagramSocket.java
@@ -56,7 +56,7 @@ public class DatagramSocket implements Closeable {
/**
* Constructs a UDP datagram socket which is bound to any available port on
- * the localhost.
+ * the local host using a wildcard address.
*
* @throws SocketException
* if an error occurs while creating or binding the socket.
@@ -67,34 +67,34 @@ public class DatagramSocket implements Closeable {
/**
* Constructs a UDP datagram socket which is bound to the specific port
- * {@code aPort} on the localhost. Valid values for {@code aPort} are
+ * {@code aPort} on the local host using a wildcard address. Valid values for {@code aPort} are
* between 0 and 65535 inclusive.
*
* @param aPort
- * the port to bind on the localhost.
+ * the port to bind on the local host.
* @throws SocketException
* if an error occurs while creating or binding the socket.
*/
public DatagramSocket(int aPort) throws SocketException {
checkPort(aPort);
- createSocket(aPort, Inet4Address.ANY);
+ createSocket(aPort, Inet6Address.ANY);
}
/**
- * Constructs a UDP datagram socket which is bound to the specific local
- * address {@code addr} on port {@code aPort}. Valid values for {@code
- * aPort} are between 0 and 65535 inclusive.
+ * Constructs a UDP datagram socket which is bound to the specific local address {@code addr} on
+ * port {@code aPort}. Valid values for {@code aPort} are between 0 and 65535 inclusive. If
+ * {@code addr} is {@code null} the socket will be bound to a wildcard address.
*
* @param aPort
- * the port to bind on the localhost.
+ * the port to bind on the local host.
* @param addr
- * the address to bind on the localhost.
+ * the address to bind on the local host.
* @throws SocketException
* if an error occurs while creating or binding the socket.
*/
public DatagramSocket(int aPort, InetAddress addr) throws SocketException {
checkPort(aPort);
- createSocket(aPort, (addr == null) ? Inet4Address.ANY : addr);
+ createSocket(aPort, (addr == null) ? Inet6Address.ANY : addr);
}
private void checkPort(int aPort) {
@@ -443,7 +443,7 @@ public class DatagramSocket implements Closeable {
private void ensureBound() throws SocketException {
if (!isBound()) {
- impl.bind(0, Inet4Address.ANY);
+ impl.bind(0, Inet6Address.ANY);
isBound = true;
}
}
@@ -467,7 +467,7 @@ public class DatagramSocket implements Closeable {
InetAddress addr;
if (localAddr == null) {
localPort = 0;
- addr = Inet4Address.ANY;
+ addr = Inet6Address.ANY;
} else {
if (!(localAddr instanceof InetSocketAddress)) {
throw new IllegalArgumentException("Local address not an InetSocketAddress: " +
diff --git a/luni/src/main/java/java/net/DatagramSocketImpl.java b/luni/src/main/java/java/net/DatagramSocketImpl.java
index 1a39987..c5e7d70 100644
--- a/luni/src/main/java/java/net/DatagramSocketImpl.java
+++ b/luni/src/main/java/java/net/DatagramSocketImpl.java
@@ -43,13 +43,13 @@ public abstract class DatagramSocketImpl implements SocketOptions {
}
/**
- * Binds the datagram socket to the given localhost/port. Sockets must be
+ * Binds the datagram socket to the given local host/port. Sockets must be
* bound prior to attempting to send or receive data.
*
* @param port
- * the port on the localhost to bind.
+ * the port on the local host to bind to.
* @param addr
- * the address on the multihomed localhost to bind.
+ * the address on the multihomed local host to bind to.
* @throws SocketException
* if an error occurs while binding, for example, if the port
* has been already bound.
diff --git a/luni/src/main/java/java/net/HttpURLConnection.java b/luni/src/main/java/java/net/HttpURLConnection.java
index 4e5b4ee..2a70729 100644
--- a/luni/src/main/java/java/net/HttpURLConnection.java
+++ b/luni/src/main/java/java/net/HttpURLConnection.java
@@ -134,15 +134,23 @@ import java.util.Arrays;
* used to control how many idle connections to each server will be held.
*
* <p>By default, this implementation of {@code HttpURLConnection} requests that
- * servers use gzip compression. Since {@link #getContentLength()} returns the
- * number of bytes transmitted, you cannot use that method to predict how many
- * bytes can be read from {@link #getInputStream()}. Instead, read that stream
- * until it is exhausted: when {@link InputStream#read} returns -1. Gzip
- * compression can be disabled by setting the acceptable encodings in the
- * request header: <pre> {@code
+ * servers use gzip compression and it automatically decompresses the data for
+ * callers of {@link #getInputStream()}. The Content-Encoding and Content-Length
+ * response headers are cleared in this case. Gzip compression can be disabled by
+ * setting the acceptable encodings in the request header: <pre> {@code
* urlConnection.setRequestProperty("Accept-Encoding", "identity");
* }</pre>
*
+ * <p>Setting the Accept-Encoding request header explicitly disables automatic
+ * decompression and leaves the response headers intact; callers must handle
+ * decompression as needed, according to the Content-Encoding header of the
+ * response.
+ *
+ * <p>{@link #getContentLength()} returns the number of bytes transmitted and
+ * cannot be used to predict how many bytes can be read from
+ * {@link #getInputStream()} for compressed streams. Instead, read that stream
+ * until it is exhausted, i.e. when {@link InputStream#read} returns -1.
+ *
* <h3>Handling Network Sign-On</h3>
* Some Wi-Fi networks block Internet access until the user clicks through a
* sign-on page. Such sign-on pages are typically presented by using HTTP
diff --git a/luni/src/main/java/java/net/Inet6Address.java b/luni/src/main/java/java/net/Inet6Address.java
index 8ab0f8d..347f43a 100644
--- a/luni/src/main/java/java/net/Inet6Address.java
+++ b/luni/src/main/java/java/net/Inet6Address.java
@@ -43,7 +43,7 @@ public final class Inet6Address extends InetAddress {
*/
public static final InetAddress LOOPBACK =
new Inet6Address(new byte[] {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 },
- "localhost", 0);
+ "ip6-localhost", 0);
private boolean scope_id_set;
private int scope_id;
diff --git a/luni/src/main/java/java/net/InetAddress.java b/luni/src/main/java/java/net/InetAddress.java
index 5cfa15a..581e1bd 100644
--- a/luni/src/main/java/java/net/InetAddress.java
+++ b/luni/src/main/java/java/net/InetAddress.java
@@ -202,10 +202,10 @@ public class InetAddress implements Serializable {
/**
* Gets all IP addresses associated with the given {@code host} identified
* by name or literal IP address. The IP address is resolved by the
- * configured name service. If the host name is empty or {@code null} an
- * {@code UnknownHostException} is thrown. If the host name is a literal IP
- * address string an array with the corresponding single {@code InetAddress}
- * is returned.
+ * configured name service. If the host name is empty or {@code null} the
+ * IP addresses of the loopback interfaces are returned. If the host name
+ * is a literal IP address string an array with the corresponding single
+ * {@code InetAddress} is returned.
*
* @param host the hostname or literal IP string to be resolved.
* @return the array of addresses associated with the specified host.
@@ -344,6 +344,19 @@ public class InetAddress implements Serializable {
}
/**
+ * Returns the hostname if known, or the result of {@code #getHostAddress}.
+ * Unlike {@link #getHostName}, this method will never cause a DNS lookup.
+ *
+ * @hide For libcore situations that must avoid DNS lookups.
+ */
+ public String getHostString() {
+ if (hostName == null) {
+ return getHostAddress();
+ }
+ return hostName;
+ }
+
+ /**
* Returns the fully qualified hostname corresponding to this IP address.
*/
public String getCanonicalHostName() {
diff --git a/luni/src/main/java/java/net/InetSocketAddress.java b/luni/src/main/java/java/net/InetSocketAddress.java
index a366133..1b3eabe 100644
--- a/luni/src/main/java/java/net/InetSocketAddress.java
+++ b/luni/src/main/java/java/net/InetSocketAddress.java
@@ -21,7 +21,7 @@ import java.io.IOException;
import java.io.ObjectInputStream;
/**
- * This class represents a socket endpoint described by a IP address and a port
+ * This class represents the address of a socket endpoint described by a IP address and a port
* number. It is a concrete implementation of {@code SocketAddress} for IP.
*/
public class InetSocketAddress extends SocketAddress {
@@ -48,8 +48,7 @@ public class InetSocketAddress extends SocketAddress {
* no specified address. The range for valid port numbers is between 0 and
* 65535 inclusive.
*
- * @param port
- * the specified port number to which this socket is bound.
+ * @param port the port number of the socket endpoint.
*/
public InetSocketAddress(int port) {
this((InetAddress) null, port);
@@ -58,19 +57,17 @@ public class InetSocketAddress extends SocketAddress {
/**
* Creates a socket endpoint with the given port number {@code port} and
* {@code address}. The range for valid port numbers is between 0 and 65535
- * inclusive. If {@code address} is {@code null} this socket is bound to the
- * IPv4 wildcard address.
+ * inclusive. If {@code address} is {@code null} the address is set to a
+ * wildcard address.
*
- * @param port
- * the specified port number to which this socket is bound.
- * @param address
- * the specified address to which this socket is bound.
+ * @param address the address of the socket endpoint.
+ * @param port the port number of the socket endpoint.
*/
public InetSocketAddress(InetAddress address, int port) {
if (port < 0 || port > 65535) {
throw new IllegalArgumentException("port=" + port);
}
- this.addr = (address == null) ? Inet4Address.ANY : address;
+ this.addr = (address == null) ? Inet6Address.ANY : address;
this.hostname = null;
this.port = port;
}
@@ -81,10 +78,8 @@ public class InetSocketAddress extends SocketAddress {
* {@code null}. The range for valid port numbers is between 0 and 65535
* inclusive.
*
- * @param port
- * the specified port number to which this socket is bound.
- * @param host
- * the specified hostname to which this socket is bound.
+ * @param host the hostname of the socket endpoint.
+ * @param port the port number of the socket endpoint.
*/
public InetSocketAddress(String host, int port) {
this(host, port, true);
@@ -117,28 +112,25 @@ public class InetSocketAddress extends SocketAddress {
* hostname into an {@code InetAddress}. The address field is marked as
* unresolved.
*
- * @param host
- * the specified hostname to which this socket is bound.
- * @param port
- * the specified port number to which this socket is bound.
+ * @param host the hostname of the socket endpoint.
+ * @param port the port number of the socket endpoint.
* @return the created InetSocketAddress instance.
- * @throws IllegalArgumentException
- * if the hostname {@code host} is {@code null} or the port is
- * not in the range between 0 and 65535.
+ * @throws IllegalArgumentException if the hostname {@code host} is {@code null} or the port is
+ * not in the range between 0 and 65535.
*/
public static InetSocketAddress createUnresolved(String host, int port) {
return new InetSocketAddress(host, port, false);
}
/**
- * Returns this socket address' port.
+ * Returns the socket endpoint's port.
*/
public final int getPort() {
return port;
}
/**
- * Returns this socket address' address.
+ * Returns the socket endpoint's address.
*/
public final InetAddress getAddress() {
return addr;
@@ -159,7 +151,7 @@ public class InetSocketAddress extends SocketAddress {
* @since 1.7
*/
public final String getHostString() {
- return (hostname != null) ? hostname : addr.getHostAddress();
+ return (hostname != null) ? hostname : addr.getHostString();
}
/**
@@ -186,9 +178,8 @@ public class InetSocketAddress extends SocketAddress {
* socket endpoints are equal if the IP address or the hostname of both are
* equal and they are bound to the same port.
*
- * @param socketAddr
- * the object to be tested for equality.
- * @return {@code true} if this socket and the given socket object {@code
+ * @param socketAddr the object to be tested for equality.
+ * @return {@code true} if this socket endpoint and the given socket endpoint {@code
* socketAddr} are equal, {@code false} otherwise.
*/
@Override
diff --git a/luni/src/main/java/java/net/PlainSocketImpl.java b/luni/src/main/java/java/net/PlainSocketImpl.java
index 4e5ba44..0c50f62 100644
--- a/luni/src/main/java/java/net/PlainSocketImpl.java
+++ b/luni/src/main/java/java/net/PlainSocketImpl.java
@@ -301,16 +301,12 @@ public class PlainSocketImpl extends SocketImpl {
* Gets the InetAddress of the SOCKS proxy server.
*/
private InetAddress socksGetServerAddress() throws UnknownHostException {
- String proxyName;
// get socks server address from proxy. It is unnecessary to check
// "socksProxyHost" property, since all proxy setting should be
// determined by ProxySelector.
- InetSocketAddress addr = (InetSocketAddress) proxy.address();
- proxyName = addr.getHostName();
- if (proxyName == null) {
- proxyName = addr.getAddress().getHostAddress();
- }
- return InetAddress.getByName(proxyName);
+ InetSocketAddress socketAddress = (InetSocketAddress) proxy.address();
+ InetAddress address = socketAddress.getAddress();
+ return (address != null) ? address : InetAddress.getByName(socketAddress.getHostName());
}
/**
diff --git a/luni/src/main/java/java/net/ServerSocket.java b/luni/src/main/java/java/net/ServerSocket.java
index 72b197f..a2cd9c6 100644
--- a/luni/src/main/java/java/net/ServerSocket.java
+++ b/luni/src/main/java/java/net/ServerSocket.java
@@ -65,24 +65,25 @@ public class ServerSocket implements Closeable {
}
/**
- * Constructs a new {@code ServerSocket} instance bound to the given {@code port}.
- * The backlog is set to 50. If {@code port == 0}, a port will be assigned by the OS.
+ * Constructs a new {@code ServerSocket} instance bound to the given {@code port} using a
+ * wildcard address. The backlog is set to 50. If {@code port == 0}, a port will be assigned by
+ * the OS.
*
* @throws IOException if an error occurs while creating the socket.
*/
public ServerSocket(int port) throws IOException {
- this(port, DEFAULT_BACKLOG, Inet4Address.ANY);
+ this(port, DEFAULT_BACKLOG, Inet6Address.ANY);
}
/**
- * Constructs a new {@code ServerSocket} instance bound to the given {@code port}.
- * The backlog is set to {@code backlog}.
+ * Constructs a new {@code ServerSocket} instance bound to the given {@code port} using a
+ * wildcard address. The backlog is set to {@code backlog}.
* If {@code port == 0}, a port will be assigned by the OS.
*
* @throws IOException if an error occurs while creating the socket.
*/
public ServerSocket(int port, int backlog) throws IOException {
- this(port, backlog, Inet4Address.ANY);
+ this(port, backlog, Inet6Address.ANY);
}
/**
@@ -97,7 +98,7 @@ public class ServerSocket implements Closeable {
checkListen(port);
this.impl = factory != null ? factory.createSocketImpl()
: new PlainServerSocketImpl();
- InetAddress addr = (localAddress == null) ? Inet4Address.ANY : localAddress;
+ InetAddress addr = (localAddress == null) ? Inet6Address.ANY : localAddress;
synchronized (this) {
impl.create(true);
@@ -316,7 +317,7 @@ public class ServerSocket implements Closeable {
InetAddress addr;
int port;
if (localAddr == null) {
- addr = Inet4Address.ANY;
+ addr = Inet6Address.ANY;
port = 0;
} else {
if (!(localAddr instanceof InetSocketAddress)) {
diff --git a/luni/src/main/java/java/net/Socket.java b/luni/src/main/java/java/net/Socket.java
index 5dd350a..7ee6b05 100644
--- a/luni/src/main/java/java/net/Socket.java
+++ b/luni/src/main/java/java/net/Socket.java
@@ -41,7 +41,7 @@ public class Socket implements Closeable {
private boolean isInputShutdown = false;
private boolean isOutputShutdown = false;
- private InetAddress localAddress = Inet4Address.ANY;
+ private InetAddress localAddress = Inet6Address.ANY;
private final Object connectLock = new Object();
@@ -211,7 +211,7 @@ public class Socket implements Closeable {
/**
* Creates a new streaming socket connected to the target host specified by
* the parameters {@code dstAddress} and {@code dstPort}. The socket is
- * bound to any available port on the local host.
+ * bound to any available port on the local host using a wildcard address.
*
* @param dstAddress
* the target host address to connect to.
@@ -228,16 +228,18 @@ public class Socket implements Closeable {
/**
* Creates a new streaming socket connected to the target host specified by
- * the parameters {@code dstAddress} and {@code dstPort}. On the local
- * endpoint the socket is bound to the given address {@code localAddress} on
- * port {@code localPort}.
+ * the parameters {@code dstAddress} and {@code dstPort}.
+ *
+ * <p>On the local endpoint the socket is bound to the given address {@code localAddress} on
+ * port {@code localPort}. If {@code localAddress} is {@code null} the socket will be bound to a
+ * wildcard address.
*
* @param dstAddress
* the target host address to connect to.
* @param dstPort
* the port on the target host to connect to.
* @param localAddress
- * the address on the local host to bind to.
+ * the address on the local host to bind to, or null.
* @param localPort
* the port on the local host to bind to.
* @throws IOException
@@ -253,7 +255,7 @@ public class Socket implements Closeable {
/**
* Creates a new streaming or datagram socket connected to the target host
* specified by the parameters {@code addr} and {@code port}. The socket is
- * bound to any available port on the local host.
+ * bound to any available port on the local host using a wildcard address.
*
* @param addr
* the Internet address to connect to.
@@ -315,7 +317,7 @@ public class Socket implements Closeable {
isConnected = false;
// RI compatibility: the RI returns the any address (but the original local port) after
// close.
- localAddress = Inet4Address.ANY;
+ localAddress = Inet6Address.ANY;
impl.close();
}
@@ -330,7 +332,7 @@ public class Socket implements Closeable {
isConnected = false;
// RI compatibility: the RI returns the any address (but the original local port) after
// close.
- localAddress = Inet4Address.ANY;
+ localAddress = Inet6Address.ANY;
impl.onClose();
}
@@ -577,7 +579,7 @@ public class Socket implements Closeable {
throw new IllegalArgumentException("Local port out of range: " + localPort);
}
- InetAddress addr = localAddress == null ? Inet4Address.ANY : localAddress;
+ InetAddress addr = localAddress == null ? Inet6Address.ANY : localAddress;
synchronized (this) {
impl.create(streaming);
isCreated = true;
@@ -772,7 +774,7 @@ public class Socket implements Closeable {
InetAddress addr;
if (localAddr == null) {
port = 0;
- addr = Inet4Address.ANY;
+ addr = Inet6Address.ANY;
} else {
if (!(localAddr instanceof InetSocketAddress)) {
throw new IllegalArgumentException("Local address not an InetSocketAddress: " +
@@ -875,7 +877,7 @@ public class Socket implements Closeable {
// options on create
// impl.create(true);
if (!usingSocks()) {
- impl.bind(Inet4Address.ANY, 0);
+ impl.bind(Inet6Address.ANY, 0);
}
isBound = true;
}
diff --git a/luni/src/main/java/java/net/URL.java b/luni/src/main/java/java/net/URL.java
index dd487bc..b62ed84 100644
--- a/luni/src/main/java/java/net/URL.java
+++ b/luni/src/main/java/java/net/URL.java
@@ -331,7 +331,7 @@ public final class URL implements Serializable {
* Virtual hosting permits unrelated sites to share an IP address. This
* method could report two otherwise unrelated URLs to be equal because
* they're hosted on the same server.</li>
- * <li><strong>The network many not be available.</strong> Two URLs could be
+ * <li><strong>The network may not be available.</strong> Two URLs could be
* equal when a network is available and unequal otherwise.</li>
* <li><strong>The network may change.</strong> The IP address for a given
* host name varies by network and over time. This is problematic for mobile
diff --git a/luni/src/main/java/java/nio/SelectorImpl.java b/luni/src/main/java/java/nio/SelectorImpl.java
index 45406b1..c73ba22 100644
--- a/luni/src/main/java/java/nio/SelectorImpl.java
+++ b/luni/src/main/java/java/nio/SelectorImpl.java
@@ -38,7 +38,6 @@ import libcore.io.IoBridge;
import libcore.io.IoUtils;
import libcore.io.Libcore;
-import static android.system.OsConstants.EINTR;
import static android.system.OsConstants.POLLERR;
import static android.system.OsConstants.POLLHUP;
import static android.system.OsConstants.POLLIN;
@@ -94,7 +93,7 @@ final class SelectorImpl extends AbstractSelector {
* configure the pipe so we can fully drain it without blocking.
*/
try {
- FileDescriptor[] pipeFds = Libcore.os.pipe();
+ FileDescriptor[] pipeFds = Libcore.os.pipe2(0);
wakeupIn = pipeFds[0];
wakeupOut = pipeFds[1];
IoUtils.setBlocking(wakeupIn, false);
@@ -183,9 +182,7 @@ final class SelectorImpl extends AbstractSelector {
try {
rc = Libcore.os.poll(pollFds.array(), (int) timeout);
} catch (ErrnoException errnoException) {
- if (errnoException.errno != EINTR) {
- throw errnoException.rethrowAsIOException();
- }
+ throw errnoException.rethrowAsIOException();
}
} finally {
if (isBlocking) {
diff --git a/luni/src/main/java/java/nio/channels/Selector.java b/luni/src/main/java/java/nio/channels/Selector.java
index 6d9b063..baa6a7f 100644
--- a/luni/src/main/java/java/nio/channels/Selector.java
+++ b/luni/src/main/java/java/nio/channels/Selector.java
@@ -78,8 +78,11 @@ public abstract class Selector implements Closeable {
public abstract boolean isOpen();
/**
- * Gets the set of registered keys. The set is immutable and is not thread-
- * safe.
+ * Gets the set of registered keys.
+ *
+ * <p>The returned set cannot be changed directly but can be modified
+ * indirectly by operations on the Selector. It should therefore not be
+ * treated as thread-safe.
*
* @return the set of registered keys.
*/
@@ -127,9 +130,11 @@ public abstract class Selector implements Closeable {
public abstract int select(long timeout) throws IOException;
/**
- * Gets the selection keys whose channels are ready for operation. The set
- * is not thread-safe and no keys may be added to it. Removing keys is
- * allowed.
+ * Gets the selection keys whose channels are ready for operation.
+ *
+ * <p>Keys cannot be added to the set directly. Keys can be removed.
+ * The set can be modified indirectly by operations on the Selector. It
+ * should therefore not be treated as thread-safe.
*
* @return the selection keys whose channels are ready for operation.
* @throws ClosedSelectorException
diff --git a/luni/src/main/java/java/nio/charset/CharsetEncoder.java b/luni/src/main/java/java/nio/charset/CharsetEncoder.java
index 9217bba..9d53328 100644
--- a/luni/src/main/java/java/nio/charset/CharsetEncoder.java
+++ b/luni/src/main/java/java/nio/charset/CharsetEncoder.java
@@ -194,13 +194,19 @@ public abstract class CharsetEncoder {
throw illegalStateException();
}
+ if (!cb.hasRemaining()) {
+ return true;
+ }
+
CodingErrorAction originalMalformedInputAction = malformedInputAction;
CodingErrorAction originalUnmappableCharacterAction = unmappableCharacterAction;
onMalformedInput(CodingErrorAction.REPORT);
onUnmappableCharacter(CodingErrorAction.REPORT);
try {
- encode(cb);
- return true;
+ ByteBuffer buf = encode(cb);
+ // b/18474439: ICU will return U_ZERO_ERROR but produce an output buffer
+ // of size zero when it encounters an ignorable codepoint.
+ return buf.hasRemaining();
} catch (CharacterCodingException e) {
return false;
} finally {
@@ -436,24 +442,33 @@ public abstract class CharsetEncoder {
* <p>
* This method will call {@link #implFlush(ByteBuffer) implFlush}. Some
* encoders may need to write some bytes to the output buffer when they have
- * read all input characters, subclasses can overridden
- * {@link #implFlush(ByteBuffer) implFlush} to perform writing action.
+ * read all input characters. Subclasses can override
+ * {@link #implFlush(ByteBuffer) implFlush} to perform any writes that are
+ * required at the end of the output sequence, such as footers and other
+ * metadata.
* <p>
- * The maximum number of written bytes won't larger than
- * {@link ByteBuffer#remaining() out.remaining()}. If some encoder wants to
+ * The maximum number of written bytes won't be larger than
+ * {@link ByteBuffer#remaining() out.remaining()}. If the encoder wants to
* write more bytes than the output buffer's available remaining space, then
- * <code>CoderResult.OVERFLOW</code> will be returned, and this method
- * must be called again with a byte buffer that has free space. Otherwise
- * this method will return <code>CoderResult.UNDERFLOW</code>, which
- * means one encoding process has been completed successfully.
+ * it will return {@code CoderResult.OVERFLOW}. This method must then be
+ * called again with a byte buffer that has free space.
+ * <p>
+ * If the encoder was asked to flush its output when its input is incomplete,
+ * (because it ends with an unpaired surrogate, say) it may return
+ * {@code CodeResult.MALFORMED}.
+ * <p>
+ * In all other cases the encoder will return {@code CoderResult.UNDERFLOW},
+ * which signifies that all the input so far has been successfully encoded.
* <p>
* During the flush, the output buffer's position will be changed
* accordingly, while its mark and limit will be intact.
+ * <p>
+ * This method is a no-op if the encoder has already been flushed.
*
- * @param out
- * the given output buffer.
- * @return <code>CoderResult.UNDERFLOW</code> or
- * <code>CoderResult.OVERFLOW</code>.
+ * @param out the given output buffer.
+ * @return {@code CoderResult.UNDERFLOW} or
+ * {@code CoderResult.OVERFLOW} or
+ * {@code CoderResult.MALFORMED}
* @throws IllegalStateException
* if this encoder isn't already flushed or at end of input.
*/
@@ -461,6 +476,9 @@ public abstract class CharsetEncoder {
if (state != FLUSHED && state != END_OF_INPUT) {
throw illegalStateException();
}
+ if (state == FLUSHED) {
+ return CoderResult.UNDERFLOW;
+ }
CoderResult result = implFlush(out);
if (result == CoderResult.UNDERFLOW) {
state = FLUSHED;
diff --git a/luni/src/main/java/java/security/Provider.java b/luni/src/main/java/java/security/Provider.java
index 1704b58..1a64ecc 100644
--- a/luni/src/main/java/java/security/Provider.java
+++ b/luni/src/main/java/java/security/Provider.java
@@ -368,8 +368,8 @@ public abstract class Provider extends Properties {
}
/**
- * Get the service of the specified type
- *
+ * Get the service of the specified {@code type} (e.g. "SecureRandom",
+ * "Signature").
*/
synchronized Provider.Service getService(String type) {
updatePropertyServiceTable();
diff --git a/luni/src/main/java/java/security/Security.java b/luni/src/main/java/java/security/Security.java
index b859f9a..aeb189f 100644
--- a/luni/src/main/java/java/security/Security.java
+++ b/luni/src/main/java/java/security/Security.java
@@ -19,6 +19,8 @@ package java.security;
import java.io.BufferedInputStream;
import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.Reader;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.HashMap;
@@ -47,16 +49,25 @@ public final class Security {
// - load security properties files
// - load statically registered providers
// - if no provider description file found then load default providers
+ // Note: Getting the input stream for the security.properties file is factored into its own
+ // function, which will be intercepted during boot image creation.
static {
boolean loaded = false;
+ Reader input = null;
try {
- InputStream configStream = Security.class.getResourceAsStream("security.properties");
- InputStream input = new BufferedInputStream(configStream);
+ input = getSecurityPropertiesReader();
secprops.load(input);
loaded = true;
- configStream.close();
} catch (Exception ex) {
System.logE("Could not load 'security.properties'", ex);
+ } finally {
+ if (input != null) {
+ try {
+ input.close();
+ } catch (Exception ex) {
+ System.logW("Could not close 'security.properties'", ex);
+ }
+ }
}
if (!loaded) {
registerDefaultProviders();
@@ -64,6 +75,11 @@ public final class Security {
Engine.door = new SecurityDoor();
}
+ private static Reader getSecurityPropertiesReader() throws Exception {
+ InputStream configStream = Security.class.getResourceAsStream("security.properties");
+ return new InputStreamReader(new BufferedInputStream(configStream), "ISO-8859-1");
+ }
+
/**
* This class can't be instantiated.
*/
diff --git a/luni/src/main/java/java/security/Signature.java b/luni/src/main/java/java/security/Signature.java
index a39d59b..b11abaa 100644
--- a/luni/src/main/java/java/security/Signature.java
+++ b/luni/src/main/java/java/security/Signature.java
@@ -172,7 +172,12 @@ public abstract class Signature extends SignatureSpi {
throw new NoSuchAlgorithmException("Unknown algorithm: " + algorithm);
}
- SpiAndProvider spiAndProvider = tryAlgorithm(null, provider, algorithm);
+ SpiAndProvider spiAndProvider;
+ try {
+ spiAndProvider = tryAlgorithm(null, provider, algorithm);
+ } catch (InvalidKeyException e) {
+ throw new IllegalStateException("InvalidKeyException thrown when key == null", e);
+ }
if (spiAndProvider == null) {
if (provider == null) {
throw new NoSuchAlgorithmException("No provider found for " + algorithm);
@@ -187,24 +192,36 @@ public abstract class Signature extends SignatureSpi {
return new SignatureImpl(algorithm, provider);
}
- private static Engine.SpiAndProvider tryAlgorithm(Key key, Provider provider, String algorithm) {
+ /**
+ * @throws InvalidKeyException if the specified key cannot be used to
+ * initialize any provider.
+ */
+ private static Engine.SpiAndProvider tryAlgorithm(
+ Key key, Provider provider, String algorithm) throws InvalidKeyException {
if (provider != null) {
Provider.Service service = provider.getService(SERVICE, algorithm);
if (service == null) {
return null;
}
- return tryAlgorithmWithProvider(key, service);
+ return tryAlgorithmWithProvider(null, service);
}
ArrayList<Provider.Service> services = ENGINE.getServices(algorithm);
- if (services == null) {
+ if (services == null || services.isEmpty()) {
return null;
}
+ boolean keySupported = false;
for (Provider.Service service : services) {
- Engine.SpiAndProvider sap = tryAlgorithmWithProvider(key, service);
- if (sap != null) {
- return sap;
+ if (key == null || service.supportsParameter(key)) {
+ keySupported = true;
+ Engine.SpiAndProvider sap = tryAlgorithmWithProvider(key, service);
+ if (sap != null) {
+ return sap;
+ }
}
}
+ if (!keySupported) {
+ throw new InvalidKeyException("No provider supports the provided key");
+ }
return null;
}
@@ -245,6 +262,16 @@ public abstract class Signature extends SignatureSpi {
}
/**
+ * Returns the {@code SignatureSpi} backing this {@code Signature} or {@code null} if no
+ * {@code SignatureSpi} is backing this {@code Signature}.
+ *
+ * @hide
+ */
+ public SignatureSpi getCurrentSpi() {
+ return null;
+ }
+
+ /**
* Returns the name of the algorithm of this {@code Signature}.
*
* @return the name of the algorithm of this {@code Signature}.
@@ -651,7 +678,7 @@ public abstract class Signature extends SignatureSpi {
@Override
void ensureProviderChosen() {
- getSpi(null);
+ getSpi();
}
@Override
@@ -709,8 +736,11 @@ public abstract class Signature extends SignatureSpi {
/**
* Makes sure a CipherSpi that matches this type is selected.
+ *
+ * @throws InvalidKeyException if the specified key cannot be used to
+ * initialize this signature.
*/
- private SignatureSpi getSpi(Key key) {
+ private SignatureSpi getSpi(Key key) throws InvalidKeyException {
synchronized (initLock) {
if (spiImpl != null && key == null) {
return spiImpl;
@@ -732,7 +762,18 @@ public abstract class Signature extends SignatureSpi {
* Convenience call when the Key is not available.
*/
private SignatureSpi getSpi() {
- return getSpi(null);
+ try {
+ return getSpi(null);
+ } catch (InvalidKeyException e) {
+ throw new IllegalStateException("InvalidKeyException thrown when key == null", e);
+ }
+ }
+
+ @Override
+ public SignatureSpi getCurrentSpi() {
+ synchronized (initLock) {
+ return spiImpl;
+ }
}
}
}
diff --git a/luni/src/main/java/java/text/BreakIterator.java b/luni/src/main/java/java/text/BreakIterator.java
index 81545b2..051ea15 100644
--- a/luni/src/main/java/java/text/BreakIterator.java
+++ b/luni/src/main/java/java/text/BreakIterator.java
@@ -18,8 +18,6 @@
package java.text;
import java.util.Locale;
-import libcore.icu.ICU;
-import libcore.icu.NativeBreakIterator;
/**
* Locates boundaries in text. This class defines a protocol for objects that
@@ -230,29 +228,19 @@ public abstract class BreakIterator implements Cloneable {
*/
public static final int DONE = -1;
- // the wrapped ICU implementation
- NativeBreakIterator wrapped;
-
/**
* Default constructor, for use by subclasses.
*/
protected BreakIterator() {
}
- /*
- * wrapping constructor
- */
- BreakIterator(NativeBreakIterator iterator) {
- wrapped = iterator;
- }
-
/**
* Returns an array of locales for which custom {@code BreakIterator} instances
* are available.
* <p>Note that Android does not support user-supplied locale service providers.
*/
public static Locale[] getAvailableLocales() {
- return ICU.getAvailableBreakIteratorLocales();
+ return com.ibm.icu.text.BreakIterator.getAvailableLocales();
}
/**
@@ -270,7 +258,8 @@ public abstract class BreakIterator implements Cloneable {
* characters using the given locale.
*/
public static BreakIterator getCharacterInstance(Locale locale) {
- return new RuleBasedBreakIterator(NativeBreakIterator.getCharacterInstance(locale));
+ return new IcuIteratorWrapper(
+ com.ibm.icu.text.BreakIterator.getCharacterInstance(locale));
}
/**
@@ -288,7 +277,8 @@ public abstract class BreakIterator implements Cloneable {
* line breaks using the given locale.
*/
public static BreakIterator getLineInstance(Locale locale) {
- return new RuleBasedBreakIterator(NativeBreakIterator.getLineInstance(locale));
+ return new IcuIteratorWrapper(
+ com.ibm.icu.text.BreakIterator.getLineInstance(locale));
}
/**
@@ -306,7 +296,8 @@ public abstract class BreakIterator implements Cloneable {
* sentence-breaks using the given locale.
*/
public static BreakIterator getSentenceInstance(Locale locale) {
- return new RuleBasedBreakIterator(NativeBreakIterator.getSentenceInstance(locale));
+ return new IcuIteratorWrapper(
+ com.ibm.icu.text.BreakIterator.getSentenceInstance(locale));
}
/**
@@ -324,7 +315,8 @@ public abstract class BreakIterator implements Cloneable {
* word-breaks using the given locale.
*/
public static BreakIterator getWordInstance(Locale locale) {
- return new RuleBasedBreakIterator(NativeBreakIterator.getWordInstance(locale));
+ return new IcuIteratorWrapper(
+ com.ibm.icu.text.BreakIterator.getWordInstance(locale));
}
/**
@@ -339,7 +331,7 @@ public abstract class BreakIterator implements Cloneable {
* false} otherwise.
*/
public boolean isBoundary(int offset) {
- return wrapped.isBoundary(offset);
+ return false;
}
/**
@@ -354,7 +346,7 @@ public abstract class BreakIterator implements Cloneable {
* if the offset is invalid.
*/
public int preceding(int offset) {
- return wrapped.preceding(offset);
+ return 0;
}
/**
@@ -366,10 +358,6 @@ public abstract class BreakIterator implements Cloneable {
* the new text string to be analyzed.
*/
public void setText(String newText) {
- if (newText == null) {
- throw new NullPointerException("newText == null");
- }
- wrapped.setText(newText);
}
/**
@@ -466,9 +454,7 @@ public abstract class BreakIterator implements Cloneable {
@Override
public Object clone() {
try {
- BreakIterator cloned = (BreakIterator) super.clone();
- cloned.wrapped = (NativeBreakIterator) wrapped.clone();
- return cloned;
+ return (BreakIterator) super.clone();
} catch (CloneNotSupportedException e) {
throw new AssertionError(e);
}
diff --git a/luni/src/main/java/java/text/ChoiceFormat.java b/luni/src/main/java/java/text/ChoiceFormat.java
index 014b8c7..3d3cb3a 100644
--- a/luni/src/main/java/java/text/ChoiceFormat.java
+++ b/luni/src/main/java/java/text/ChoiceFormat.java
@@ -303,37 +303,16 @@ public class ChoiceFormat extends NumberFormat {
}
/**
- * Returns the double value which is closest to the specified double but
- * larger.
- *
- * @param value
- * a double value.
- * @return the next larger double value.
+ * Equivalent to {@link Math#nextUp(double)}.
*/
public static final double nextDouble(double value) {
- if (value == Double.POSITIVE_INFINITY) {
- return value;
- }
- long bits;
- // Handle -0.0
- if (value == 0) {
- bits = 0;
- } else {
- bits = Double.doubleToLongBits(value);
- }
- return Double.longBitsToDouble(value < 0 ? bits - 1 : bits + 1);
+ return Math.nextUp(value);
}
/**
- * Returns the double value which is closest to the specified double but
- * either larger or smaller as specified.
- *
- * @param value
- * a double value.
- * @param increment
- * {@code true} to get the next larger value, {@code false} to
- * get the previous smaller value.
- * @return the next larger or smaller double value.
+ * Equivalent to {@link Math#nextUp(double)} if {@code increment == true}, and
+ * {@link Math#nextAfter(double, double)} with {@code direction == Double.NEGATIVE_INFINITY}
+ * otherwise.
*/
public static double nextDouble(double value, boolean increment) {
return increment ? nextDouble(value) : previousDouble(value);
@@ -385,25 +364,11 @@ public class ChoiceFormat extends NumberFormat {
}
/**
- * Returns the double value which is closest to the specified double but
- * smaller.
- *
- * @param value
- * a double value.
- * @return the next smaller double value.
+ * Equivalent to {@link Math#nextAfter(double, double)} with
+ * {@code direction == Double.NEGATIVE_INFINITY}.
*/
public static final double previousDouble(double value) {
- if (value == Double.NEGATIVE_INFINITY) {
- return value;
- }
- long bits;
- // Handle 0.0
- if (value == 0) {
- bits = 0x8000000000000000L;
- } else {
- bits = Double.doubleToLongBits(value);
- }
- return Double.longBitsToDouble(value <= 0 ? bits + 1 : bits - 1);
+ return Math.nextAfter(value, Double.NEGATIVE_INFINITY);
}
/**
@@ -453,9 +418,30 @@ public class ChoiceFormat extends NumberFormat {
if (i != 0) {
buffer.append('|');
}
- String previous = String.valueOf(previousDouble(choiceLimits[i]));
- String limit = String.valueOf(choiceLimits[i]);
- if (previous.length() < limit.length()) {
+
+ final String previous = String.valueOf(previousDouble(choiceLimits[i]));
+ final String limit = String.valueOf(choiceLimits[i]);
+
+ // Hack to make the output of toPattern parseable by another ChoiceFormat.
+ // String.valueOf() will emit "Infinity", which isn't parseable by our NumberFormat
+ // instances.
+ //
+ // Ideally, we'd just use NumberFormat.format() to emit output (to be symmetric with
+ // our usage of NumberFormat.parse()) but it's hard set the right number of significant
+ // digits in order to output a format string that's equivalent to the original input.
+ if (Double.isInfinite(choiceLimits[i]) ||
+ Double.isInfinite(previousDouble(choiceLimits[i]))) {
+ if (choiceLimits[i] < 0) {
+ buffer.append("-\u221E");
+ buffer.append('<');
+ } else {
+ buffer.append('\u221E');
+ buffer.append('<');
+ }
+ } else if (previous.length() < limit.length()) {
+ // What the... i don't even.... sigh. This is trying to figure out whether the
+ // element was a "<" or a "#". The idea being that users will specify "reasonable"
+ // quantities and calling nextDouble will result in a "longer" number in most cases.
buffer.append(previous);
buffer.append('<');
} else {
diff --git a/luni/src/main/java/java/text/DecimalFormatSymbols.java b/luni/src/main/java/java/text/DecimalFormatSymbols.java
index 2f1d4f4..006d37b 100644
--- a/luni/src/main/java/java/text/DecimalFormatSymbols.java
+++ b/luni/src/main/java/java/text/DecimalFormatSymbols.java
@@ -297,8 +297,14 @@ public class DecimalFormatSymbols implements Cloneable, Serializable {
return minusSign.charAt(0);
}
- throw new UnsupportedOperationException(
- "Minus sign spans multiple characters: " + minusSign);
+ // Return the minus sign from Locale.ROOT instead of crashing. None of libcore the parsers
+ // or formatters actually call this function, they use {@code getMinusSignString()} instead
+ // and that function always returns the correct (possibly multi-char) symbol.
+ //
+ // Callers of this method that format strings and expect them to be parseable by
+ // the "standard" parsers (or vice-versa) are hosed, but there's not much we can do to
+ // save them.
+ return '-';
}
/** @hide */
@@ -349,7 +355,15 @@ public class DecimalFormatSymbols implements Cloneable, Serializable {
if (percent.length() == 1) {
return percent.charAt(0);
}
- throw new UnsupportedOperationException("Percent spans multiple characters: " + percent);
+
+ // Return the percent sign from Locale.ROOT instead of crashing. None of the libcore parsers
+ // or formatters actually call this function, they use {@code getPercentString()} instead
+ // and that function always returns the correct (possibly multi-char) symbol.
+ //
+ // Callers of this method that format strings and expect them to be parseable by
+ // the "standard" parsers (or vice-versa) are hosed, but there's not much we can do to
+ // save them.
+ return '%';
}
/**
@@ -601,6 +615,8 @@ public class DecimalFormatSymbols implements Cloneable, Serializable {
new ObjectStreamField("serialVersionOnStream", int.class),
new ObjectStreamField("zeroDigit", char.class),
new ObjectStreamField("locale", Locale.class),
+ new ObjectStreamField("minusSignStr", String.class),
+ new ObjectStreamField("percentStr", String.class),
};
private void writeObject(ObjectOutputStream stream) throws IOException {
@@ -613,15 +629,21 @@ public class DecimalFormatSymbols implements Cloneable, Serializable {
fields.put("groupingSeparator", getGroupingSeparator());
fields.put("infinity", infinity);
fields.put("intlCurrencySymbol", intlCurrencySymbol);
- fields.put("minusSign", getMinusSign());
fields.put("monetarySeparator", getMonetaryDecimalSeparator());
fields.put("NaN", NaN);
fields.put("patternSeparator", getPatternSeparator());
- fields.put("percent", getPercent());
fields.put("perMill", getPerMill());
fields.put("serialVersionOnStream", 3);
fields.put("zeroDigit", getZeroDigit());
fields.put("locale", locale);
+
+ // Hardcode values here for backwards compatibility. These values will only be used
+ // if we're de-serializing this object on an earlier version of android.
+ fields.put("minusSign", minusSign.length() == 1 ? minusSign.charAt(0) : '-');
+ fields.put("percent", percent.length() == 1 ? percent.charAt(0) : '%');
+
+ fields.put("minusSignStr", getMinusSignString());
+ fields.put("percentStr", getPercentString());
stream.writeFields();
}
@@ -634,10 +656,26 @@ public class DecimalFormatSymbols implements Cloneable, Serializable {
setGroupingSeparator(fields.get("groupingSeparator", ','));
infinity = (String) fields.get("infinity", "");
intlCurrencySymbol = (String) fields.get("intlCurrencySymbol", "");
- setMinusSign(fields.get("minusSign", '-'));
NaN = (String) fields.get("NaN", "");
setPatternSeparator(fields.get("patternSeparator", ';'));
- setPercent(fields.get("percent", '%'));
+
+ // Special handling for minusSign and percent. If we've serialized the string versions of
+ // these fields, use them. If not, fall back to the single character versions. This can
+ // only happen if we're de-serializing an object that was written by an older version of
+ // android (something that's strongly discouraged anyway).
+ final String minusSignStr = (String) fields.get("minusSignStr", null);
+ if (minusSignStr != null) {
+ minusSign = minusSignStr;
+ } else {
+ setMinusSign(fields.get("minusSign", '-'));
+ }
+ final String percentStr = (String) fields.get("percentStr", null);
+ if (percentStr != null) {
+ percent = percentStr;
+ } else {
+ setPercent(fields.get("percent", '%'));
+ }
+
setPerMill(fields.get("perMill", '\u2030'));
setZeroDigit(fields.get("zeroDigit", '0'));
locale = (Locale) fields.get("locale", null);
diff --git a/luni/src/main/java/java/text/Format.java b/luni/src/main/java/java/text/Format.java
index 58671fa..c4dc5f0 100644
--- a/luni/src/main/java/java/text/Format.java
+++ b/luni/src/main/java/java/text/Format.java
@@ -177,23 +177,26 @@ public abstract class Format implements Serializable, Cloneable {
static boolean upTo(String string, ParsePosition position,
StringBuffer buffer, char stop) {
int index = position.getIndex(), length = string.length();
- boolean lastQuote = false, quote = false;
+
+ int numConsecutiveQuotes = 0;
+ boolean quote = false;
while (index < length) {
char ch = string.charAt(index++);
if (ch == '\'') {
- if (lastQuote) {
+ ++numConsecutiveQuotes;
+ if (numConsecutiveQuotes != 0 && numConsecutiveQuotes % 2 == 0) {
buffer.append('\'');
}
quote = !quote;
- lastQuote = true;
} else if (ch == stop && !quote) {
position.setIndex(index);
return true;
} else {
- lastQuote = false;
+ numConsecutiveQuotes = 0;
buffer.append(ch);
}
}
+
position.setIndex(index);
return false;
}
diff --git a/luni/src/main/java/java/text/RuleBasedBreakIterator.java b/luni/src/main/java/java/text/IcuIteratorWrapper.java
index a16968e..b863fa7 100644
--- a/luni/src/main/java/java/text/RuleBasedBreakIterator.java
+++ b/luni/src/main/java/java/text/IcuIteratorWrapper.java
@@ -17,7 +17,6 @@
package java.text;
-import libcore.icu.NativeBreakIterator;
/*
* Default implementation of BreakIterator. Wraps libcore.icu.NativeBreakIterator.
@@ -25,10 +24,13 @@ import libcore.icu.NativeBreakIterator;
* and we don't have Java implementations of those methods (other than the current ones, which
* forward to the wrapped NativeBreakIterator).
*/
-class RuleBasedBreakIterator extends BreakIterator {
+class IcuIteratorWrapper extends BreakIterator {
- RuleBasedBreakIterator(NativeBreakIterator iterator) {
- super(iterator);
+ /* The wrapped ICU implementation. Non-final for #clone() */
+ private com.ibm.icu.text.BreakIterator wrapped;
+
+ IcuIteratorWrapper(com.ibm.icu.text.BreakIterator iterator) {
+ wrapped = iterator;
}
@Override public int current() {
@@ -44,17 +46,6 @@ class RuleBasedBreakIterator extends BreakIterator {
return wrapped.following(offset);
}
- private void checkOffset(int offset) {
- if (!wrapped.hasText()) {
- throw new IllegalArgumentException("BreakIterator has no text");
- }
- CharacterIterator it = wrapped.getText();
- if (offset < it.getBeginIndex() || offset > it.getEndIndex()) {
- String message = "Valid range is [" + it.getBeginIndex() + " " + it.getEndIndex() + "]";
- throw new IllegalArgumentException(message);
- }
- }
-
@Override public CharacterIterator getText() {
return wrapped.getText();
}
@@ -75,10 +66,11 @@ class RuleBasedBreakIterator extends BreakIterator {
return wrapped.previous();
}
+ @Override public void setText(String newText) {
+ wrapped.setText(newText);
+ }
+
@Override public void setText(CharacterIterator newText) {
- if (newText == null) {
- throw new NullPointerException("newText == null");
- }
newText.current();
wrapped.setText(newText);
}
@@ -94,10 +86,10 @@ class RuleBasedBreakIterator extends BreakIterator {
}
@Override public boolean equals(Object o) {
- if (!(o instanceof RuleBasedBreakIterator)) {
+ if (!(o instanceof IcuIteratorWrapper)) {
return false;
}
- return wrapped.equals(((RuleBasedBreakIterator) o).wrapped);
+ return wrapped.equals(((IcuIteratorWrapper) o).wrapped);
}
@Override public String toString() {
@@ -108,9 +100,20 @@ class RuleBasedBreakIterator extends BreakIterator {
return wrapped.hashCode();
}
+ private void checkOffset(int offset) {
+ final CharacterIterator it = wrapped.getText();
+ if (it == null) {
+ throw new IllegalArgumentException("BreakIterator has no text");
+ }
+ if (offset < it.getBeginIndex() || offset > it.getEndIndex()) {
+ String message = "Valid range is [" + it.getBeginIndex() + " " + it.getEndIndex() + "]";
+ throw new IllegalArgumentException(message);
+ }
+ }
+
@Override public Object clone() {
- RuleBasedBreakIterator cloned = (RuleBasedBreakIterator) super.clone();
- cloned.wrapped = (NativeBreakIterator) wrapped.clone();
+ IcuIteratorWrapper cloned = (IcuIteratorWrapper) super.clone();
+ cloned.wrapped = (com.ibm.icu.text.BreakIterator) wrapped.clone();
return cloned;
}
}
diff --git a/luni/src/main/java/java/text/MessageFormat.java b/luni/src/main/java/java/text/MessageFormat.java
index cf306a7..f48cebd 100644
--- a/luni/src/main/java/java/text/MessageFormat.java
+++ b/luni/src/main/java/java/text/MessageFormat.java
@@ -580,6 +580,12 @@ public class MessageFormat extends Format {
}
if (format instanceof ChoiceFormat) {
String result = format.format(arg);
+ // Escape quotes in the result because the ChoiceFormat would've already
+ // dealt with them for us. In other words, any quotes that are present in the
+ // result are due to escaped quotes in the original input. We should preserve
+ // them in the output instead of having them processed again with the message
+ // format we're creating below.
+ result = result.replace("'", "''");
MessageFormat mf = new MessageFormat(result);
mf.setLocale(locale);
mf.format(objects, buffer, passedField);
diff --git a/luni/src/main/java/java/text/NumberFormat.java b/luni/src/main/java/java/text/NumberFormat.java
index a1f10d4..2526ffc 100644
--- a/luni/src/main/java/java/text/NumberFormat.java
+++ b/luni/src/main/java/java/text/NumberFormat.java
@@ -492,6 +492,10 @@ public abstract class NumberFormat extends Format {
* to format floating-point numbers typically between 0 and 1 (with 1 being 100%).
* A value such as 0.53 will be treated as 53%, but 53.0 (or the integer 53) will be
* treated as 5,300%, which is rarely what you intended.
+ *
+ * <p>Non-integer percentages will be rounded according to the rounding mode,
+ * so by default 0.142 will be 14% but 0.148 will be 15%. If you want fractional
+ * percentages, use {@link #setMaximumFractionDigits}.
*/
public static final NumberFormat getPercentInstance() {
return getPercentInstance(Locale.getDefault());
@@ -505,6 +509,10 @@ public abstract class NumberFormat extends Format {
* to format floating-point numbers typically between 0 and 1 (with 1 being 100%).
* A value such as 0.53 will be treated as 53%, but 53.0 (or the integer 53) will be
* treated as 5,300%, which is rarely what you intended.
+ *
+ * <p>Non-integer percentages will be rounded according to the rounding mode,
+ * so by default 0.142 will be 14% but 0.148 will be 15%. If you want fractional
+ * percentages, use {@link #setMaximumFractionDigits}.
*/
public static NumberFormat getPercentInstance(Locale locale) {
if (locale == null) {
diff --git a/luni/src/main/java/java/text/SimpleDateFormat.java b/luni/src/main/java/java/text/SimpleDateFormat.java
index 8f83ff7..4e7a950 100644
--- a/luni/src/main/java/java/text/SimpleDateFormat.java
+++ b/luni/src/main/java/java/text/SimpleDateFormat.java
@@ -91,7 +91,16 @@ import libcore.icu.TimeZoneNames;
* <tr> <td>{@code ''}</td> <td>single quote</td> <td>(Literal)</td> <td>{@code 'o''clock'}:o'clock</td> </tr>
* </table>
*
- * <p>Fractional seconds are handled specially: they're zero-padded on the <i>right</i>.
+ * <p>Note that {@code 'S'} represents fractional seconds and not millisecond values.
+ * They will be padded on the left or on the right or both depending on the number of
+ * {@code 'S'} in the pattern. For example, the number of fractional seconds in a
+ * {@code Date} where {@code Date.getTime() == 1000006} are {@code 0.006} or
+ * {@code (6 / 1000)}. This leads to the following formatting:
+ * <ul>
+ * <li> {@code "S" => "0"} </li>
+ * <li> {@code "SSS" => "006" } </li>
+ * <li> {@code "SSSSSS" => "006000" }</li>
+ * </ul>
*
* <p>The two pattern characters {@code L} and {@code c} are ICU-compatible extensions, not
* available in the RI or in Android before Android 2.3 (Gingerbread, API level 9). These
diff --git a/luni/src/main/java/java/util/Calendar.java b/luni/src/main/java/java/util/Calendar.java
index fc4cef6..6057547 100644
--- a/luni/src/main/java/java/util/Calendar.java
+++ b/luni/src/main/java/java/util/Calendar.java
@@ -810,7 +810,9 @@ public abstract class Calendar implements Serializable, Cloneable, Comparable<Ca
}
/**
- * Returns a shallow copy of this {@code Calendar} with the same properties.
+ * Returns a partially deep copy of this {@code Calendar}; all fields from
+ * from the {@code Calendar} class are cloned (deep copy) but fields from
+ * subclasses aren't (shallow copy).
*/
@Override
public Object clone() {
diff --git a/luni/src/main/java/java/util/Collections.java b/luni/src/main/java/java/util/Collections.java
index 4541d64..dc4161f 100644
--- a/luni/src/main/java/java/util/Collections.java
+++ b/luni/src/main/java/java/util/Collections.java
@@ -102,6 +102,10 @@ public class Collections {
throw new IndexOutOfBoundsException();
}
+ @Override public Iterator iterator() {
+ return EMPTY_ITERATOR;
+ }
+
private Object readResolve() {
return Collections.EMPTY_LIST;
}
@@ -1422,21 +1426,21 @@ public class Collections {
if (!(list instanceof RandomAccess)) {
ListIterator<? extends Comparable<? super T>> it = list.listIterator();
while (it.hasNext()) {
- int result;
- if ((result = -it.next().compareTo(object)) <= 0) {
- if (result == 0) {
- return it.previousIndex();
- }
+ final int result = it.next().compareTo(object);
+ if (result == 0) {
+ return it.previousIndex();
+ } else if (result > 0) {
return -it.previousIndex() - 1;
}
}
return -list.size() - 1;
}
- int low = 0, mid = list.size(), high = mid - 1, result = -1;
+ int low = 0, mid = list.size(), high = mid - 1, result = 1;
while (low <= high) {
mid = (low + high) >>> 1;
- if ((result = -list.get(mid).compareTo(object)) > 0) {
+ result = list.get(mid).compareTo(object);
+ if (result < 0) {
low = mid + 1;
} else if (result == 0) {
return mid;
@@ -1444,7 +1448,7 @@ public class Collections {
high = mid - 1;
}
}
- return -mid - (result < 0 ? 1 : 2);
+ return -mid - (result > 0 ? 1 : 2);
}
/**
@@ -1477,21 +1481,21 @@ public class Collections {
if (!(list instanceof RandomAccess)) {
ListIterator<? extends T> it = list.listIterator();
while (it.hasNext()) {
- int result;
- if ((result = -comparator.compare(it.next(), object)) <= 0) {
- if (result == 0) {
- return it.previousIndex();
- }
+ final int result = comparator.compare(it.next(), object);
+ if (result == 0) {
+ return it.previousIndex();
+ } else if (result > 0) {
return -it.previousIndex() - 1;
}
}
return -list.size() - 1;
}
- int low = 0, mid = list.size(), high = mid - 1, result = -1;
+ int low = 0, mid = list.size(), high = mid - 1, result = 1;
while (low <= high) {
mid = (low + high) >>> 1;
- if ((result = -comparator.compare(list.get(mid), object)) > 0) {
+ result = comparator.compare(list.get(mid), object);
+ if (result < 0) {
low = mid + 1;
} else if (result == 0) {
return mid;
@@ -1499,7 +1503,7 @@ public class Collections {
high = mid - 1;
}
}
- return -mid - (result < 0 ? 1 : 2);
+ return -mid - (result > 0 ? 1 : 2);
}
/**
@@ -1860,13 +1864,23 @@ public class Collections {
*/
@SuppressWarnings("unchecked")
public static <T extends Comparable<? super T>> void sort(List<T> list) {
- Object[] array = list.toArray();
- Arrays.sort(array);
- int i = 0;
- ListIterator<T> it = list.listIterator();
- while (it.hasNext()) {
- it.next();
- it.set((T) array[i++]);
+ // Note that we can't use instanceof here since ArrayList isn't final and
+ // subclasses might make arbitrary use of array and modCount.
+ if (list.getClass() == ArrayList.class) {
+ ArrayList<T> arrayList = (ArrayList<T>) list;
+ Object[] array = arrayList.array;
+ int end = arrayList.size();
+ Arrays.sort(array, 0, end);
+ arrayList.modCount++;
+ } else {
+ Object[] array = list.toArray();
+ Arrays.sort(array);
+ int i = 0;
+ ListIterator<T> it = list.listIterator();
+ while (it.hasNext()) {
+ it.next();
+ it.set((T) array[i++]);
+ }
}
}
@@ -1879,13 +1893,21 @@ public class Collections {
*/
@SuppressWarnings("unchecked")
public static <T> void sort(List<T> list, Comparator<? super T> comparator) {
- T[] array = list.toArray((T[]) new Object[list.size()]);
- Arrays.sort(array, comparator);
- int i = 0;
- ListIterator<T> it = list.listIterator();
- while (it.hasNext()) {
- it.next();
- it.set(array[i++]);
+ if (list.getClass() == ArrayList.class) {
+ ArrayList<T> arrayList = (ArrayList<T>) list;
+ T[] array = (T[]) arrayList.array;
+ int end = arrayList.size();
+ Arrays.sort(array, 0, end, comparator);
+ arrayList.modCount++;
+ } else {
+ T[] array = list.toArray((T[]) new Object[list.size()]);
+ Arrays.sort(array, comparator);
+ int i = 0;
+ ListIterator<T> it = list.listIterator();
+ while (it.hasNext()) {
+ it.next();
+ it.set(array[i++]);
+ }
}
}
diff --git a/luni/src/main/java/java/util/ComparableTimSort.java b/luni/src/main/java/java/util/ComparableTimSort.java
index aba7573..f3da001 100644
--- a/luni/src/main/java/java/util/ComparableTimSort.java
+++ b/luni/src/main/java/java/util/ComparableTimSort.java
@@ -94,7 +94,7 @@ class ComparableTimSort {
private final int[] runLen;
/**
- * Asserts have been placed in if-statements for performace. To enable them,
+ * Asserts have been placed in if-statements for performance. To enable them,
* set this field to true and enable them in VM with a command line flag.
* If you modify this class, please do test the asserts!
*/
@@ -363,11 +363,28 @@ class ComparableTimSort {
*/
private void mergeCollapse() {
while (stackSize > 1) {
- int n = stackSize - 2;
+ final int n = stackSize - 2;
if (n > 0 && runLen[n-1] <= runLen[n] + runLen[n+1]) {
- if (runLen[n - 1] < runLen[n + 1])
- n--;
- mergeAt(n);
+ // Merge the smaller of runLen[n-1] or runLen[n + 1] with runLen[n].
+ if (runLen[n - 1] < runLen[n + 1]) {
+ // runLen[n-1] is smallest. Merge runLen[n] into runLen[n - 1], leaving
+ // runLen[n+1] as the new runLen[n].
+ mergeAt(n - 1);
+ // n is now stackSize - 1, the top of the stack.
+ // Fix for http://b/19493779
+ // Because we modified runLen[n - 1] we might have affected invariant 1 as far
+ // back as runLen[n - 3]. Check we did not violate it.
+ if (n > 2 && runLen[n-3] <= runLen[n-2] + runLen[n-1]) {
+ // Avoid leaving invariant 1 still violated on the next loop by also merging
+ // runLen[n] into runLen[n - 1].
+ mergeAt(n - 1);
+ // Now the last three elements in the stack will again be the only elements
+ // that might break the invariant and we can loop again safely.
+ }
+ } else {
+ // runLen[n+1] is smallest. Merge runLen[n + 1] into runLen[n].
+ mergeAt(n);
+ }
} else if (runLen[n] <= runLen[n + 1]) {
mergeAt(n);
} else {
diff --git a/luni/src/main/java/java/util/Date.java b/luni/src/main/java/java/util/Date.java
index b4de055..253d2e8 100644
--- a/luni/src/main/java/java/util/Date.java
+++ b/luni/src/main/java/java/util/Date.java
@@ -47,7 +47,10 @@ public class Date implements Serializable, Cloneable, Comparable<Date> {
private static final long serialVersionUID = 7523967970034938905L;
// Used by parse()
- private static final int CREATION_YEAR = new Date().getYear();
+ // Keep in a static inner class to allow compile-time initialization of Date.
+ private static class CreationYear {
+ private static final int VALUE = new Date().getYear();
+ }
private transient long milliseconds;
@@ -539,7 +542,7 @@ public class Date implements Serializable, Cloneable, Comparable<Date> {
if (second == -1) {
second = 0;
}
- if (year < (CREATION_YEAR - 80)) {
+ if (year < (CreationYear.VALUE - 80)) {
year += 2000;
} else if (year < 100) {
year += 1900;
@@ -688,21 +691,23 @@ public class Date implements Serializable, Cloneable, Comparable<Date> {
}
/**
- * Returns a string representation of this {@code Date}.
- * The formatting is equivalent to using a {@code SimpleDateFormat} with
- * the format string "EEE MMM dd HH:mm:ss zzz yyyy", which looks something
- * like "Tue Jun 22 13:07:00 PDT 1999". The current default time zone and
- * locale are used. If you need control over the time zone or locale,
- * use {@code SimpleDateFormat} instead.
+ * Returns a string representation of this {@code Date}. The formatting is equivalent to
+ * using a {@code SimpleDateFormat} with the format string "EEE MMM dd HH:mm:ss zzz yyyy",
+ * which looks something like "Tue Jun 22 13:07:00 PDT 1999". While the current default time
+ * zone is used, all formatting and timezone names follow {@code Locale.US}. If you need control
+ * over the time zone or locale, use {@code SimpleDateFormat} instead.
*/
@Override
public String toString() {
// TODO: equivalent to the following one-liner, though that's slower on stingray
// at 476us versus 69us...
- // return new SimpleDateFormat("EEE MMM dd HH:mm:ss zzz yyyy").format(d);
+ // return new SimpleDateFormat("EEE MMM dd HH:mm:ss zzz yyyy").format(d, Locale.US);
LocaleData localeData = LocaleData.get(Locale.US);
- Calendar cal = new GregorianCalendar(milliseconds);
- TimeZone tz = cal.getTimeZone();
+
+ TimeZone tz = TimeZone.getDefault();
+ Calendar cal = new GregorianCalendar(tz, Locale.US);
+ cal.setTimeInMillis(milliseconds);
+
StringBuilder result = new StringBuilder();
result.append(localeData.shortWeekdayNames[cal.get(Calendar.DAY_OF_WEEK)]);
result.append(' ');
@@ -716,7 +721,7 @@ public class Date implements Serializable, Cloneable, Comparable<Date> {
result.append(':');
appendTwoDigits(result, cal.get(Calendar.SECOND));
result.append(' ');
- result.append(tz.getDisplayName(tz.inDaylightTime(this), TimeZone.SHORT));
+ result.append(tz.getDisplayName(tz.inDaylightTime(this), TimeZone.SHORT, Locale.US));
result.append(' ');
result.append(cal.get(Calendar.YEAR));
return result.toString();
diff --git a/luni/src/main/java/java/util/EnumMap.java b/luni/src/main/java/java/util/EnumMap.java
index dfacb46..eee6ff4 100644
--- a/luni/src/main/java/java/util/EnumMap.java
+++ b/luni/src/main/java/java/util/EnumMap.java
@@ -36,9 +36,9 @@ public class EnumMap<K extends Enum<K>, V> extends AbstractMap<K, V> implements
private Class<K> keyType;
- transient Enum[] keys;
+ transient K[] keys;
- transient Object[] values;
+ transient V[] values;
transient boolean[] hasMapping;
@@ -48,8 +48,7 @@ public class EnumMap<K extends Enum<K>, V> extends AbstractMap<K, V> implements
private transient EnumMapEntrySet<K, V> entrySet = null;
- private static class Entry<KT extends Enum<KT>, VT> extends
- MapEntry<KT, VT> {
+ private static class Entry<KT extends Enum<KT>, VT> extends MapEntry<KT, VT> {
private final EnumMap<KT, VT> enumMap;
private final int ordinal;
@@ -57,10 +56,9 @@ public class EnumMap<K extends Enum<K>, V> extends AbstractMap<K, V> implements
Entry(KT theKey, VT theValue, EnumMap<KT, VT> em) {
super(theKey, theValue);
enumMap = em;
- ordinal = ((Enum) theKey).ordinal();
+ ordinal = theKey.ordinal();
}
- @SuppressWarnings("unchecked")
@Override
public boolean equals(Object object) {
if (!enumMap.hasMapping[ordinal]) {
@@ -68,7 +66,7 @@ public class EnumMap<K extends Enum<K>, V> extends AbstractMap<K, V> implements
}
boolean isEqual = false;
if (object instanceof Map.Entry) {
- Map.Entry<KT, VT> entry = (Map.Entry<KT, VT>) object;
+ Map.Entry<?, ?> entry = (Map.Entry<?, ?>) object;
Object enumKey = entry.getKey();
if (key.equals(enumKey)) {
Object theValue = entry.getValue();
@@ -84,37 +82,32 @@ public class EnumMap<K extends Enum<K>, V> extends AbstractMap<K, V> implements
@Override
public int hashCode() {
- return (enumMap.keys[ordinal] == null ? 0 : enumMap.keys[ordinal]
- .hashCode())
+ return (enumMap.keys[ordinal] == null ? 0 : enumMap.keys[ordinal].hashCode())
^ (enumMap.values[ordinal] == null ? 0
: enumMap.values[ordinal].hashCode());
}
- @SuppressWarnings("unchecked")
@Override
public KT getKey() {
checkEntryStatus();
- return (KT) enumMap.keys[ordinal];
+ return enumMap.keys[ordinal];
}
- @SuppressWarnings("unchecked")
@Override
public VT getValue() {
checkEntryStatus();
- return (VT) enumMap.values[ordinal];
+ return enumMap.values[ordinal];
}
- @SuppressWarnings("unchecked")
@Override
public VT setValue(VT value) {
checkEntryStatus();
- return enumMap.put((KT) enumMap.keys[ordinal], value);
+ return enumMap.put(enumMap.keys[ordinal], value);
}
@Override
public String toString() {
- StringBuilder result = new StringBuilder(enumMap.keys[ordinal]
- .toString());
+ StringBuilder result = new StringBuilder(enumMap.keys[ordinal].toString());
result.append("=");
result.append(enumMap.values[ordinal] == null
? "null" : enumMap.values[ordinal].toString());
@@ -128,8 +121,7 @@ public class EnumMap<K extends Enum<K>, V> extends AbstractMap<K, V> implements
}
}
- private static class EnumMapIterator<E, KT extends Enum<KT>, VT> implements
- Iterator<E> {
+ private static class EnumMapIterator<E, KT extends Enum<KT>, VT> implements Iterator<E> {
int position = 0;
int prePosition = -1;
@@ -153,13 +145,12 @@ public class EnumMap<K extends Enum<K>, V> extends AbstractMap<K, V> implements
return position != length;
}
- @SuppressWarnings("unchecked")
public E next() {
if (!hasNext()) {
throw new NoSuchElementException();
}
prePosition = position++;
- return type.get(new MapEntry(enumMap.keys[prePosition],
+ return type.get(new MapEntry<KT, VT>(enumMap.keys[prePosition],
enumMap.values[prePosition]));
}
@@ -172,13 +163,12 @@ public class EnumMap<K extends Enum<K>, V> extends AbstractMap<K, V> implements
}
@Override
- @SuppressWarnings("unchecked")
public String toString() {
if (prePosition == -1) {
return super.toString();
}
return type.get(
- new MapEntry(enumMap.keys[prePosition],
+ new MapEntry<KT, VT>(enumMap.keys[prePosition],
enumMap.values[prePosition])).toString();
}
@@ -208,8 +198,7 @@ public class EnumMap<K extends Enum<K>, V> extends AbstractMap<K, V> implements
}
@Override
- @SuppressWarnings("unchecked")
- public Iterator iterator() {
+ public Iterator<KT> iterator() {
return new EnumMapIterator<KT, KT, VT>(
new MapEntry.Type<KT, KT, VT>() {
public KT get(MapEntry<KT, VT> entry) {
@@ -219,7 +208,6 @@ public class EnumMap<K extends Enum<K>, V> extends AbstractMap<K, V> implements
}
@Override
- @SuppressWarnings("unchecked")
public boolean remove(Object object) {
if (contains(object)) {
enumMap.remove(object);
@@ -252,9 +240,8 @@ public class EnumMap<K extends Enum<K>, V> extends AbstractMap<K, V> implements
return enumMap.containsValue(object);
}
- @SuppressWarnings("unchecked")
@Override
- public Iterator iterator() {
+ public Iterator<VT> iterator() {
return new EnumMapIterator<VT, KT, VT>(
new MapEntry.Type<VT, KT, VT>() {
public VT get(MapEntry<KT, VT> entry) {
@@ -296,15 +283,14 @@ public class EnumMap<K extends Enum<K>, V> extends AbstractMap<K, V> implements
super(value, em);
}
- @SuppressWarnings("unchecked")
@Override
public E next() {
if (!hasNext()) {
throw new NoSuchElementException();
}
prePosition = position++;
- return type.get(new Entry<KT, VT>((KT) enumMap.keys[prePosition],
- (VT) enumMap.values[prePosition], enumMap));
+ return type.get(new EnumMap.Entry<KT, VT>(enumMap.keys[prePosition],
+ enumMap.values[prePosition], enumMap));
}
}
@@ -325,8 +311,8 @@ public class EnumMap<K extends Enum<K>, V> extends AbstractMap<K, V> implements
public boolean contains(Object object) {
boolean isEqual = false;
if (object instanceof Map.Entry) {
- Object enumKey = ((Map.Entry) object).getKey();
- Object enumValue = ((Map.Entry) object).getValue();
+ Object enumKey = ((Map.Entry<?, ?>) object).getKey();
+ Object enumValue = ((Map.Entry<?, ?>) object).getValue();
if (enumMap.containsKey(enumKey)) {
VT value = enumMap.get(enumKey);
if (value == null) {
@@ -352,7 +338,7 @@ public class EnumMap<K extends Enum<K>, V> extends AbstractMap<K, V> implements
@Override
public boolean remove(Object object) {
if (contains(object)) {
- enumMap.remove(((Map.Entry) object).getKey());
+ enumMap.remove(((Map.Entry<?, ?>) object).getKey());
return true;
}
return false;
@@ -369,21 +355,22 @@ public class EnumMap<K extends Enum<K>, V> extends AbstractMap<K, V> implements
return toArray(entryArray);
}
- @SuppressWarnings("unchecked")
@Override
- public Object[] toArray(Object[] array) {
+ public <T> T[] toArray(T[] array) {
int size = enumMap.size();
int index = 0;
- Object[] entryArray = array;
+ T[] entryArray = array;
if (size > array.length) {
Class<?> clazz = array.getClass().getComponentType();
- entryArray = (Object[]) Array.newInstance(clazz, size);
+ @SuppressWarnings("unchecked") T[] newArray = (T[]) Array.newInstance(clazz, size);
+ entryArray = newArray;
}
Iterator<Map.Entry<KT, VT>> iter = iterator();
for (; index < size; index++) {
Map.Entry<KT, VT> entry = iter.next();
- entryArray[index] = new MapEntry<KT, VT>(entry.getKey(), entry
- .getValue());
+ @SuppressWarnings("unchecked") T newEntry =
+ (T) new MapEntry<KT, VT>(entry.getKey(), entry.getValue());
+ entryArray[index] = newEntry;
}
if (index < array.length) {
entryArray[index] = null;
@@ -431,22 +418,27 @@ public class EnumMap<K extends Enum<K>, V> extends AbstractMap<K, V> implements
* @throws NullPointerException
* if {@code map} is {@code null}.
*/
- @SuppressWarnings("unchecked")
public EnumMap(Map<K, ? extends V> map) {
if (map instanceof EnumMap) {
- initialization((EnumMap<K, V>) map);
+ @SuppressWarnings("unchecked") EnumMap<K, ? extends V> enumMap =
+ (EnumMap<K, ? extends V>) map;
+ initialization(enumMap);
} else {
if (map.isEmpty()) {
throw new IllegalArgumentException("map is empty");
}
Iterator<K> iter = map.keySet().iterator();
K enumKey = iter.next();
- Class clazz = enumKey.getClass();
- if (clazz.isEnum()) {
- initialization(clazz);
- } else {
- initialization(clazz.getSuperclass());
+ // Confirm the key is actually an enum: Throw ClassCastException if not.
+ Enum.class.cast(enumKey);
+ Class<?> clazz = enumKey.getClass();
+ if (!clazz.isEnum()) {
+ // Each enum value can have its own subclass. In this case we want the abstract
+ // super-class which has the values() method.
+ clazz = clazz.getSuperclass();
}
+ @SuppressWarnings("unchecked") Class<K> enumClass = (Class<K>) clazz;
+ initialization(enumClass);
putAllImpl(map);
}
}
@@ -469,11 +461,10 @@ public class EnumMap<K extends Enum<K>, V> extends AbstractMap<K, V> implements
*
* @return a shallow copy of this {@code EnumMap}.
*/
- @SuppressWarnings("unchecked")
@Override
public EnumMap<K, V> clone() {
try {
- EnumMap<K, V> enumMap = (EnumMap<K, V>) super.clone();
+ @SuppressWarnings("unchecked") EnumMap<K, V> enumMap = (EnumMap<K, V>) super.clone();
enumMap.initialization(this);
return enumMap;
} catch (CloneNotSupportedException e) {
@@ -553,7 +544,6 @@ public class EnumMap<K extends Enum<K>, V> extends AbstractMap<K, V> implements
* @see #hashCode()
* @see #entrySet()
*/
- @SuppressWarnings("unchecked")
@Override
public boolean equals(Object object) {
if (this == object) {
@@ -562,7 +552,7 @@ public class EnumMap<K extends Enum<K>, V> extends AbstractMap<K, V> implements
if (!(object instanceof EnumMap)) {
return super.equals(object);
}
- EnumMap<K, V> enumMap = (EnumMap<K, V>) object;
+ @SuppressWarnings("unchecked") EnumMap<K, V> enumMap = (EnumMap<K, V>) object;
if (keyType != enumMap.keyType || size() != enumMap.size()) {
return false;
}
@@ -579,13 +569,12 @@ public class EnumMap<K extends Enum<K>, V> extends AbstractMap<K, V> implements
* if no mapping for the specified key is found.
*/
@Override
- @SuppressWarnings("unchecked")
public V get(Object key) {
if (!isValidKeyType(key)) {
return null;
}
int keyOrdinal = ((Enum) key).ordinal();
- return (V) values[keyOrdinal];
+ return values[keyOrdinal];
}
/**
@@ -627,7 +616,6 @@ public class EnumMap<K extends Enum<K>, V> extends AbstractMap<K, V> implements
* support {@code null} keys or values.
*/
@Override
- @SuppressWarnings("unchecked")
public V put(K key, V value) {
return putImpl(key, value);
}
@@ -649,7 +637,6 @@ public class EnumMap<K extends Enum<K>, V> extends AbstractMap<K, V> implements
* support {@code null} keys or values.
*/
@Override
- @SuppressWarnings("unchecked")
public void putAll(Map<? extends K, ? extends V> map) {
putAllImpl(map);
}
@@ -665,7 +652,6 @@ public class EnumMap<K extends Enum<K>, V> extends AbstractMap<K, V> implements
* if removing from this {@code EnumMap} is not supported.
*/
@Override
- @SuppressWarnings("unchecked")
public V remove(Object key) {
if (!isValidKeyType(key)) {
return null;
@@ -675,7 +661,7 @@ public class EnumMap<K extends Enum<K>, V> extends AbstractMap<K, V> implements
hasMapping[keyOrdinal] = false;
mappingsCount--;
}
- V oldValue = (V) values[keyOrdinal];
+ V oldValue = values[keyOrdinal];
values[keyOrdinal] = null;
return oldValue;
}
@@ -716,35 +702,29 @@ public class EnumMap<K extends Enum<K>, V> extends AbstractMap<K, V> implements
stream.defaultReadObject();
initialization(keyType);
int elementCount = stream.readInt();
- Enum<K> enumKey;
- Object value;
+ K enumKey;
+ V value;
for (int i = elementCount; i > 0; i--) {
- enumKey = (Enum<K>) stream.readObject();
- value = stream.readObject();
- putImpl((K) enumKey, (V) value);
+ enumKey = (K) stream.readObject();
+ value = (V) stream.readObject();
+ putImpl(enumKey, value);
}
}
private void writeObject(ObjectOutputStream stream) throws IOException {
stream.defaultWriteObject();
stream.writeInt(mappingsCount);
- Iterator<Map.Entry<K, V>> iterator = entrySet().iterator();
- while (iterator.hasNext()) {
- Map.Entry<K, V> entry = iterator.next();
+ for (Map.Entry<K, V> entry : entrySet()) {
stream.writeObject(entry.getKey());
stream.writeObject(entry.getValue());
}
}
private boolean isValidKeyType(Object key) {
- if (key != null && keyType.isInstance(key)) {
- return true;
- }
- return false;
+ return key != null && keyType.isInstance(key);
}
- @SuppressWarnings("unchecked")
- private void initialization(EnumMap enumMap) {
+ private void initialization(EnumMap<K, ? extends V> enumMap) {
keyType = enumMap.keyType;
keys = enumMap.keys;
enumSize = enumMap.enumSize;
@@ -757,20 +737,19 @@ public class EnumMap<K extends Enum<K>, V> extends AbstractMap<K, V> implements
keyType = type;
keys = Enum.getSharedConstants(keyType);
enumSize = keys.length;
- values = new Object[enumSize];
+ // The value array is actually Object[] for speed of creation. It is treated as a V[]
+ // because it is safe to do so and eliminates unchecked warning suppression throughout.
+ @SuppressWarnings("unchecked") V[] valueArray = (V[]) new Object[enumSize];
+ values = valueArray;
hasMapping = new boolean[enumSize];
}
- @SuppressWarnings("unchecked")
- private void putAllImpl(Map map) {
- Iterator iter = map.entrySet().iterator();
- while (iter.hasNext()) {
- Map.Entry entry = (Map.Entry) iter.next();
- putImpl((K) entry.getKey(), (V) entry.getValue());
+ private void putAllImpl(Map<? extends K, ? extends V> map) {
+ for (Map.Entry<? extends K, ? extends V> entry : map.entrySet()) {
+ putImpl(entry.getKey(), entry.getValue());
}
}
- @SuppressWarnings("unchecked")
private V putImpl(K key, V value) {
if (key == null) {
throw new NullPointerException("key == null");
@@ -781,7 +760,7 @@ public class EnumMap<K extends Enum<K>, V> extends AbstractMap<K, V> implements
hasMapping[keyOrdinal] = true;
mappingsCount++;
}
- V oldValue = (V) values[keyOrdinal];
+ V oldValue = values[keyOrdinal];
values[keyOrdinal] = value;
return oldValue;
}
diff --git a/luni/src/main/java/java/util/List.java b/luni/src/main/java/java/util/List.java
index 8a9e1e3..54c8b65 100644
--- a/luni/src/main/java/java/util/List.java
+++ b/luni/src/main/java/java/util/List.java
@@ -84,7 +84,8 @@ public interface List<E> extends Collection<E> {
* @throws IllegalArgumentException
* if an object cannot be added to this {@code List}.
* @throws IndexOutOfBoundsException
- * if {@code location < 0 || location > size()}
+ * if {@code location < 0 || location > size()}.
+ * @throws NullPointerException if {@code collection} is {@code null}.
*/
public boolean addAll(int location, Collection<? extends E> collection);
@@ -104,6 +105,7 @@ public interface List<E> extends Collection<E> {
* {@code List}.
* @throws IllegalArgumentException
* if an object cannot be added to this {@code List}.
+ * @throws NullPointerException if {@code collection} is {@code null}.
*/
public boolean addAll(Collection<? extends E> collection);
@@ -135,6 +137,7 @@ public interface List<E> extends Collection<E> {
* the collection of objects
* @return {@code true} if all objects in the specified collection are
* elements of this {@code List}, {@code false} otherwise.
+ * @throws NullPointerException if {@code collection} is {@code null}.
*/
public boolean containsAll(Collection<?> collection);
@@ -269,6 +272,7 @@ public interface List<E> extends Collection<E> {
* @return {@code true} if this {@code List} is modified, {@code false} otherwise.
* @throws UnsupportedOperationException
* if removing from this {@code List} is not supported.
+ * @throws NullPointerException if {@code collection} is {@code null}.
*/
public boolean removeAll(Collection<?> collection);
@@ -281,6 +285,7 @@ public interface List<E> extends Collection<E> {
* @return {@code true} if this {@code List} is modified, {@code false} otherwise.
* @throws UnsupportedOperationException
* if removing from this {@code List} is not supported.
+ * @throws NullPointerException if {@code collection} is {@code null}.
*/
public boolean retainAll(Collection<?> collection);
diff --git a/luni/src/main/java/java/util/Locale.java b/luni/src/main/java/java/util/Locale.java
index a6368e8..9b0cd87 100644
--- a/luni/src/main/java/java/util/Locale.java
+++ b/luni/src/main/java/java/util/Locale.java
@@ -99,6 +99,10 @@ import libcore.icu.ICU;
* <td><a href="http://site.icu-project.org/download/53">ICU 53</a></td>
* <td><a href="http://cldr.unicode.org/index/downloads/cldr-25">CLDR 25</a></td>
* <td><a href="http://www.unicode.org/versions/Unicode6.3.0/">Unicode 6.3</a></td></tr>
+ * <tr><td>Android 6.0 (Marshmallow)</td>
+ * <td><a href="http://site.icu-project.org/download/55">ICU 55.1</a></td>
+ * <td><a href="http://cldr.unicode.org/index/downloads/cldr-27">CLDR 27.0.1</a></td>
+ * <td><a href="http://www.unicode.org/versions/Unicode7.0.0/">Unicode 7.0</a></td></tr>
* </table>
*
* <a name="default_locale"></a><h3>Be wary of the default locale</h3>
@@ -272,17 +276,77 @@ public final class Locale implements Cloneable, Serializable {
*/
private static final String UNDETERMINED_LANGUAGE = "und";
+
/**
- * The current default locale. It is temporarily assigned to US because we
- * need a default locale to lookup the real default locale.
+ * Map of grandfathered language tags to their modern replacements.
*/
- private static Locale defaultLocale = US;
+ private static final TreeMap<String, String> GRANDFATHERED_LOCALES;
static {
- String language = System.getProperty("user.language", "en");
- String region = System.getProperty("user.region", "US");
- String variant = System.getProperty("user.variant", "");
- defaultLocale = new Locale(language, region, variant);
+ GRANDFATHERED_LOCALES = new TreeMap<String, String>(String.CASE_INSENSITIVE_ORDER);
+
+ // From http://tools.ietf.org/html/bcp47
+ //
+ // grandfathered = irregular ; non-redundant tags registered
+ // / regular ; during the RFC 3066 era
+ // irregular =
+ GRANDFATHERED_LOCALES.put("en-GB-oed", "en-GB-x-oed");
+ GRANDFATHERED_LOCALES.put("i-ami", "ami");
+ GRANDFATHERED_LOCALES.put("i-bnn", "bnn");
+ GRANDFATHERED_LOCALES.put("i-default", "en-x-i-default");
+ GRANDFATHERED_LOCALES.put("i-enochian", "und-x-i-enochian");
+ GRANDFATHERED_LOCALES.put("i-hak", "hak");
+ GRANDFATHERED_LOCALES.put("i-klingon", "tlh");
+ GRANDFATHERED_LOCALES.put("i-lux", "lb");
+ GRANDFATHERED_LOCALES.put("i-mingo", "see-x-i-mingo");
+ GRANDFATHERED_LOCALES.put("i-navajo", "nv");
+ GRANDFATHERED_LOCALES.put("i-pwn", "pwn");
+ GRANDFATHERED_LOCALES.put("i-tao", "tao");
+ GRANDFATHERED_LOCALES.put("i-tay", "tay");
+ GRANDFATHERED_LOCALES.put("i-tsu", "tsu");
+ GRANDFATHERED_LOCALES.put("sgn-BE-FR", "sfb");
+ GRANDFATHERED_LOCALES.put("sgn-BE-NL", "vgt");
+ GRANDFATHERED_LOCALES.put("sgn-CH-DE", "sgg");
+
+ // regular =
+ GRANDFATHERED_LOCALES.put("art-lojban", "jbo");
+ GRANDFATHERED_LOCALES.put("cel-gaulish", "xtg-x-cel-gaulish");
+ GRANDFATHERED_LOCALES.put("no-bok", "nb");
+ GRANDFATHERED_LOCALES.put("no-nyn", "nn");
+ GRANDFATHERED_LOCALES.put("zh-guoyu", "cmn");
+ GRANDFATHERED_LOCALES.put("zh-hakka", "hak");
+ GRANDFATHERED_LOCALES.put("zh-min", "nan-x-zh-min");
+ GRANDFATHERED_LOCALES.put("zh-min-nan", "nan");
+ GRANDFATHERED_LOCALES.put("zh-xiang", "hsn");
+ }
+
+ private static class NoImagePreloadHolder {
+ /**
+ * The default locale, returned by {@code Locale.getDefault()}.
+ * Initialize the default locale from the system properties.
+ */
+ private static Locale defaultLocale = Locale.getDefaultLocaleFromSystemProperties();
+ }
+
+ /**
+ * Returns the default locale from system properties.
+ *
+ * @hide visible for testing.
+ */
+ public static Locale getDefaultLocaleFromSystemProperties() {
+ final String languageTag = System.getProperty("user.locale", "");
+
+ final Locale defaultLocale;
+ if (!languageTag.isEmpty()) {
+ defaultLocale = Locale.forLanguageTag(languageTag);
+ } else {
+ String language = System.getProperty("user.language", "en");
+ String region = System.getProperty("user.region", "US");
+ String variant = System.getProperty("user.variant", "");
+ defaultLocale = new Locale(language, region, variant);
+ }
+
+ return defaultLocale;
}
/**
@@ -684,12 +748,13 @@ public final class Locale implements Cloneable, Serializable {
final String normalizedValue = value.toLowerCase(Locale.ROOT).replace('_', '-');
final String[] subtags = normalizedValue.split("-");
+ final char normalizedKey = Character.toLowerCase(key);
// Lengths for subtags in the private use extension should be [1, 8] chars.
// For all other extensions, they should be [2, 8] chars.
//
// http://www.rfc-editor.org/rfc/bcp/bcp47.txt
- final int minimumLength = (key == PRIVATE_USE_EXTENSION) ? 1 : 2;
+ final int minimumLength = (normalizedKey == PRIVATE_USE_EXTENSION) ? 1 : 2;
for (String subtag : subtags) {
if (!isValidBcp47Alphanum(subtag, minimumLength, 8)) {
throw new IllformedLocaleException(
@@ -699,14 +764,14 @@ public final class Locale implements Cloneable, Serializable {
// We need to take special action in the case of unicode extensions,
// since we claim to understand their keywords and attributes.
- if (key == UNICODE_LOCALE_EXTENSION) {
+ if (normalizedKey == UNICODE_LOCALE_EXTENSION) {
// First clear existing attributes and keywords.
extensions.clear();
attributes.clear();
parseUnicodeExtension(subtags, keywords, attributes);
} else {
- extensions.put(key, normalizedValue);
+ extensions.put(normalizedKey, normalizedValue);
}
return this;
@@ -926,6 +991,27 @@ public final class Locale implements Cloneable, Serializable {
this.unicodeKeywords = Collections.unmodifiableMap(keywordsCopy);
this.extensions = Collections.unmodifiableMap(extensionsCopy);
} else {
+
+ // The locales ja_JP_JP and th_TH_TH are ill formed since their variant is too
+ // short, however they have been used to represent a locale with the japanese imperial
+ // calendar and thai numbering respectively. We add an extension in their constructor
+ // to modernize them.
+ if ("ja".equals(language) && "JP".equals(country) && "JP".equals(variant)) {
+ Map<String, String> keywordsCopy = new TreeMap<>(unicodeKeywords);
+ keywordsCopy.put("ca", "japanese");
+ unicodeKeywords = keywordsCopy;
+ } else if ("th".equals(language) && "TH".equals(country) && "TH".equals(variant)) {
+ Map<String, String> keywordsCopy = new TreeMap<>(unicodeKeywords);
+ keywordsCopy.put("nu", "thai");
+ unicodeKeywords = keywordsCopy;
+ }
+
+ if (!unicodeKeywords.isEmpty() || !unicodeAttributes.isEmpty()) {
+ Map<Character, String> extensionsCopy = new TreeMap<>(extensions);
+ addUnicodeExtensionToExtensionsMap(unicodeAttributes, unicodeKeywords, extensionsCopy);
+ extensions = extensionsCopy;
+ }
+
this.unicodeAttributes = unicodeAttributes;
this.unicodeKeywords = unicodeKeywords;
this.extensions = extensions;
@@ -1006,7 +1092,7 @@ public final class Locale implements Cloneable, Serializable {
* Instead, use this method to look it up for each use.
*/
public static Locale getDefault() {
- return defaultLocale;
+ return NoImagePreloadHolder.defaultLocale;
}
/**
@@ -1600,7 +1686,7 @@ public final class Locale implements Cloneable, Serializable {
throw new NullPointerException("locale == null");
}
String languageTag = locale.toLanguageTag();
- defaultLocale = locale;
+ NoImagePreloadHolder.defaultLocale = locale;
ICU.setDefaultLocale(languageTag);
}
@@ -2020,49 +2106,6 @@ public final class Locale implements Cloneable, Serializable {
return adjusted;
}
- /**
- * Map of grandfathered language tags to their modern replacements.
- */
- private static final TreeMap<String, String> GRANDFATHERED_LOCALES;
-
- static {
- GRANDFATHERED_LOCALES = new TreeMap<String, String>(String.CASE_INSENSITIVE_ORDER);
-
- // From http://tools.ietf.org/html/bcp47
- //
- // grandfathered = irregular ; non-redundant tags registered
- // / regular ; during the RFC 3066 era
- // irregular =
- GRANDFATHERED_LOCALES.put("en-GB-oed", "en-GB-x-oed");
- GRANDFATHERED_LOCALES.put("i-ami", "ami");
- GRANDFATHERED_LOCALES.put("i-bnn", "bnn");
- GRANDFATHERED_LOCALES.put("i-default", "en-x-i-default");
- GRANDFATHERED_LOCALES.put("i-enochian", "und-x-i-enochian");
- GRANDFATHERED_LOCALES.put("i-hak", "hak");
- GRANDFATHERED_LOCALES.put("i-klingon", "tlh");
- GRANDFATHERED_LOCALES.put("i-lux", "lb");
- GRANDFATHERED_LOCALES.put("i-mingo", "see-x-i-mingo");
- GRANDFATHERED_LOCALES.put("i-navajo", "nv");
- GRANDFATHERED_LOCALES.put("i-pwn", "pwn");
- GRANDFATHERED_LOCALES.put("i-tao", "tao");
- GRANDFATHERED_LOCALES.put("i-tay", "tay");
- GRANDFATHERED_LOCALES.put("i-tsu", "tsu");
- GRANDFATHERED_LOCALES.put("sgn-BE-FR", "sfb");
- GRANDFATHERED_LOCALES.put("sgn-BE-NL", "vgt");
- GRANDFATHERED_LOCALES.put("sgn-CH-DE", "sgg");
-
- // regular =
- GRANDFATHERED_LOCALES.put("art-lojban", "jbo");
- GRANDFATHERED_LOCALES.put("cel-gaulish", "xtg-x-cel-gaulish");
- GRANDFATHERED_LOCALES.put("no-bok", "nb");
- GRANDFATHERED_LOCALES.put("no-nyn", "nn");
- GRANDFATHERED_LOCALES.put("zh-guoyu", "cmn");
- GRANDFATHERED_LOCALES.put("zh-hakka", "hak");
- GRANDFATHERED_LOCALES.put("zh-min", "nan-x-zh-min");
- GRANDFATHERED_LOCALES.put("zh-min-nan", "nan");
- GRANDFATHERED_LOCALES.put("zh-xiang", "hsn");
- }
-
private static String convertGrandfatheredTag(String original) {
final String converted = GRANDFATHERED_LOCALES.get(original);
return converted != null ? converted : original;
@@ -2117,7 +2160,7 @@ public final class Locale implements Cloneable, Serializable {
return extensionKeyIndex;
}
- final String key = subtags[extensionKeyIndex];
+ final String key = subtags[extensionKeyIndex].toLowerCase(Locale.ROOT);
if (extensions.containsKey(key.charAt(0))) {
return extensionKeyIndex;
}
@@ -2129,7 +2172,7 @@ public final class Locale implements Cloneable, Serializable {
// Mark the start of the next extension. Also keep track of whether this
// is a private use extension, and throw an error if it doesn't come last.
extensionKeyIndex = i;
- if ("x".equals(subtag)) {
+ if ("x".equals(subtag.toLowerCase(Locale.ROOT))) {
privateUseExtensionIndex = i;
} else if (privateUseExtensionIndex != -1) {
// The private use extension must come last.
@@ -2152,7 +2195,7 @@ public final class Locale implements Cloneable, Serializable {
return extensionKeyIndex;
}
- final String key = subtags[extensionKeyIndex];
+ final String key = subtags[extensionKeyIndex].toLowerCase(Locale.ROOT);
if (extensions.containsKey(key.charAt(0))) {
return extensionKeyIndex;
}
diff --git a/luni/src/main/java/java/util/TimSort.java b/luni/src/main/java/java/util/TimSort.java
index ffe4e17..1a566c2 100644
--- a/luni/src/main/java/java/util/TimSort.java
+++ b/luni/src/main/java/java/util/TimSort.java
@@ -119,7 +119,7 @@ class TimSort<T> {
private final int[] runLen;
/**
- * Asserts have been placed in if-statements for performace. To enable them,
+ * Asserts have been placed in if-statements for performance. To enable them,
* set this field to true and enable them in VM with a command line flag.
* If you modify this class, please do test the asserts!
*/
@@ -397,11 +397,29 @@ class TimSort<T> {
*/
private void mergeCollapse() {
while (stackSize > 1) {
- int n = stackSize - 2;
+ final int n = stackSize - 2;
if (n > 0 && runLen[n-1] <= runLen[n] + runLen[n+1]) {
- if (runLen[n - 1] < runLen[n + 1])
- n--;
- mergeAt(n);
+ // Merge the smaller of runLen[n-1] or runLen[n + 1] with runLen[n].
+ if (runLen[n - 1] < runLen[n + 1]) {
+ // runLen[n-1] is smallest. Merge runLen[n] into runLen[n - 1], leaving
+ // runLen[n+1] as the new runLen[n].
+ mergeAt(n - 1);
+ // n is now stackSize - 1, the top of the stack.
+
+ // Fix for http://b/19493779
+ // Because we modified runLen[n - 1] we might have affected invariant 1 as far
+ // back as runLen[n - 3]. Check we did not violate it.
+ if (n > 2 && runLen[n-3] <= runLen[n-2] + runLen[n-1]) {
+ // Avoid leaving invariant 1 still violated on the next loop by also merging
+ // runLen[n] into runLen[n - 1].
+ mergeAt(n - 1);
+ // Now the last three elements in the stack will again be the only elements
+ // that might break the invariant and we can loop again safely.
+ }
+ } else {
+ // runLen[n+1] is smallest. Merge runLen[n + 1] into runLen[n].
+ mergeAt(n);
+ }
} else if (runLen[n] <= runLen[n + 1]) {
mergeAt(n);
} else {
diff --git a/luni/src/main/java/java/util/TimeZone.java b/luni/src/main/java/java/util/TimeZone.java
index 854a4a6..d7beb91 100644
--- a/luni/src/main/java/java/util/TimeZone.java
+++ b/luni/src/main/java/java/util/TimeZone.java
@@ -68,7 +68,51 @@ import org.apache.harmony.luni.internal.util.TimezoneGetter;
public abstract class TimeZone implements Serializable, Cloneable {
private static final long serialVersionUID = 3581463369166924961L;
- private static final Pattern CUSTOM_ZONE_ID_PATTERN = Pattern.compile("^GMT[-+](\\d{1,2})(:?(\\d\\d))?$");
+ /**
+ * Helper class to parse a custom timezone. This is in a separate class as regular expressions
+ * cannot be compile-time initialized, so that static field is separated out from TimeZone
+ * proper.
+ */
+ private final static class CustomTimeZoneParser {
+ private static final Pattern CUSTOM_ZONE_ID_PATTERN =
+ Pattern.compile("^GMT[-+](\\d{1,2})(:?(\\d\\d))?$");
+
+ private CustomTimeZoneParser() {}
+
+ /**
+ * Returns a new SimpleTimeZone for an ID of the form "GMT[+|-]hh[[:]mm]", or null.
+ */
+ private static TimeZone getCustomTimeZone(String id) {
+ Matcher m = CUSTOM_ZONE_ID_PATTERN.matcher(id);
+ if (!m.matches()) {
+ return null;
+ }
+
+ int hour;
+ int minute = 0;
+ try {
+ hour = Integer.parseInt(m.group(1));
+ if (m.group(3) != null) {
+ minute = Integer.parseInt(m.group(3));
+ }
+ } catch (NumberFormatException impossible) {
+ throw new AssertionError(impossible);
+ }
+
+ if (hour < 0 || hour > 23 || minute < 0 || minute > 59) {
+ return null;
+ }
+
+ char sign = id.charAt(3);
+ int raw = (hour * 3600000) + (minute * 60000);
+ if (sign == '-') {
+ raw = -raw;
+ }
+
+ String cleanId = String.format((Locale) null, "GMT%c%02d:%02d", sign, hour, minute);
+ return new SimpleTimeZone(raw, cleanId);
+ }
+ }
/**
* The short display name style, such as {@code PDT}. Requests for this
@@ -368,7 +412,7 @@ public abstract class TimeZone implements Serializable, Cloneable {
// Custom time zone?
if (zone == null && id.length() > 3 && id.startsWith("GMT")) {
- zone = getCustomTimeZone(id);
+ zone = CustomTimeZoneParser.getCustomTimeZone(id);
}
// We never return null; on failure we return the equivalent of "GMT".
@@ -376,40 +420,6 @@ public abstract class TimeZone implements Serializable, Cloneable {
}
/**
- * Returns a new SimpleTimeZone for an ID of the form "GMT[+|-]hh[[:]mm]", or null.
- */
- private static TimeZone getCustomTimeZone(String id) {
- Matcher m = CUSTOM_ZONE_ID_PATTERN.matcher(id);
- if (!m.matches()) {
- return null;
- }
-
- int hour;
- int minute = 0;
- try {
- hour = Integer.parseInt(m.group(1));
- if (m.group(3) != null) {
- minute = Integer.parseInt(m.group(3));
- }
- } catch (NumberFormatException impossible) {
- throw new AssertionError(impossible);
- }
-
- if (hour < 0 || hour > 23 || minute < 0 || minute > 59) {
- return null;
- }
-
- char sign = id.charAt(3);
- int raw = (hour * 3600000) + (minute * 60000);
- if (sign == '-') {
- raw = -raw;
- }
-
- String cleanId = String.format("GMT%c%02d:%02d", sign, hour, minute);
- return new SimpleTimeZone(raw, cleanId);
- }
-
- /**
* Returns true if {@code timeZone} has the same rules as this time zone.
*
* <p>The base implementation returns true if both time zones have the same
diff --git a/luni/src/main/java/java/util/concurrent/AbstractExecutorService.java b/luni/src/main/java/java/util/concurrent/AbstractExecutorService.java
index 23e68bb..26649a8 100644
--- a/luni/src/main/java/java/util/concurrent/AbstractExecutorService.java
+++ b/luni/src/main/java/java/util/concurrent/AbstractExecutorService.java
@@ -5,6 +5,7 @@
*/
package java.util.concurrent;
+
import java.util.*;
/**
diff --git a/luni/src/main/java/java/util/concurrent/ArrayBlockingQueue.java b/luni/src/main/java/java/util/concurrent/ArrayBlockingQueue.java
index 3cfe6d5..9dca1b3 100644
--- a/luni/src/main/java/java/util/concurrent/ArrayBlockingQueue.java
+++ b/luni/src/main/java/java/util/concurrent/ArrayBlockingQueue.java
@@ -5,13 +5,15 @@
*/
package java.util.concurrent;
-import java.util.concurrent.locks.Condition;
-import java.util.concurrent.locks.ReentrantLock;
+
+import java.lang.ref.WeakReference;
+import java.util.Arrays;
import java.util.AbstractQueue;
import java.util.Collection;
import java.util.Iterator;
import java.util.NoSuchElementException;
-import java.lang.ref.WeakReference;
+import java.util.concurrent.locks.Condition;
+import java.util.concurrent.locks.ReentrantLock;
// BEGIN android-note
// removed link to collections framework docs
@@ -46,7 +48,7 @@ import java.lang.ref.WeakReference;
*
* @since 1.5
* @author Doug Lea
- * @param <E> the type of elements held in this collection
+ * @param <E> the type of elements held in this queue
*/
public class ArrayBlockingQueue<E> extends AbstractQueue<E>
implements BlockingQueue<E>, java.io.Serializable {
@@ -95,14 +97,7 @@ public class ArrayBlockingQueue<E> extends AbstractQueue<E>
// Internal helper methods
/**
- * Circularly increment i.
- */
- final int inc(int i) {
- return (++i == items.length) ? 0 : i;
- }
-
- /**
- * Circularly decrement i.
+ * Circularly decrements array index i.
*/
final int dec(int i) {
return ((i == 0) ? items.length : i) - 1;
@@ -117,24 +112,15 @@ public class ArrayBlockingQueue<E> extends AbstractQueue<E>
}
/**
- * Throws NullPointerException if argument is null.
- *
- * @param v the element
- */
- private static void checkNotNull(Object v) {
- if (v == null)
- throw new NullPointerException();
- }
-
- /**
* Inserts element at current put position, advances, and signals.
* Call only when holding lock.
*/
private void enqueue(E x) {
// assert lock.getHoldCount() == 1;
// assert items[putIndex] == null;
+ final Object[] items = this.items;
items[putIndex] = x;
- putIndex = inc(putIndex);
+ if (++putIndex == items.length) putIndex = 0;
count++;
notEmpty.signal();
}
@@ -150,7 +136,7 @@ public class ArrayBlockingQueue<E> extends AbstractQueue<E>
@SuppressWarnings("unchecked")
E x = (E) items[takeIndex];
items[takeIndex] = null;
- takeIndex = inc(takeIndex);
+ if (++takeIndex == items.length) takeIndex = 0;
count--;
if (itrs != null)
itrs.elementDequeued();
@@ -171,7 +157,7 @@ public class ArrayBlockingQueue<E> extends AbstractQueue<E>
if (removeIndex == takeIndex) {
// removing front item; just advance
items[takeIndex] = null;
- takeIndex = inc(takeIndex);
+ if (++takeIndex == items.length) takeIndex = 0;
count--;
if (itrs != null)
itrs.elementDequeued();
@@ -179,17 +165,15 @@ public class ArrayBlockingQueue<E> extends AbstractQueue<E>
// an "interior" remove
// slide over all others up through putIndex.
- final int putIndex = this.putIndex;
- for (int i = removeIndex;;) {
- int next = inc(i);
- if (next != putIndex) {
- items[i] = items[next];
- i = next;
- } else {
- items[i] = null;
- this.putIndex = i;
+ for (int i = removeIndex, putIndex = this.putIndex;;) {
+ int pred = i;
+ if (++i == items.length) i = 0;
+ if (i == putIndex) {
+ items[pred] = null;
+ this.putIndex = pred;
break;
}
+ items[pred] = items[i];
}
count--;
if (itrs != null)
@@ -254,7 +238,7 @@ public class ArrayBlockingQueue<E> extends AbstractQueue<E>
int i = 0;
try {
for (E e : c) {
- checkNotNull(e);
+ if (e == null) throw new NullPointerException();
items[i++] = e;
}
} catch (ArrayIndexOutOfBoundsException ex) {
@@ -292,7 +276,7 @@ public class ArrayBlockingQueue<E> extends AbstractQueue<E>
* @throws NullPointerException if the specified element is null
*/
public boolean offer(E e) {
- checkNotNull(e);
+ if (e == null) throw new NullPointerException();
final ReentrantLock lock = this.lock;
lock.lock();
try {
@@ -315,7 +299,7 @@ public class ArrayBlockingQueue<E> extends AbstractQueue<E>
* @throws NullPointerException {@inheritDoc}
*/
public void put(E e) throws InterruptedException {
- checkNotNull(e);
+ if (e == null) throw new NullPointerException();
final ReentrantLock lock = this.lock;
lock.lockInterruptibly();
try {
@@ -338,7 +322,7 @@ public class ArrayBlockingQueue<E> extends AbstractQueue<E>
public boolean offer(E e, long timeout, TimeUnit unit)
throws InterruptedException {
- checkNotNull(e);
+ if (e == null) throw new NullPointerException();
long nanos = unit.toNanos(timeout);
final ReentrantLock lock = this.lock;
lock.lockInterruptibly();
@@ -462,11 +446,11 @@ public class ArrayBlockingQueue<E> extends AbstractQueue<E>
*/
public boolean remove(Object o) {
if (o == null) return false;
- final Object[] items = this.items;
final ReentrantLock lock = this.lock;
lock.lock();
try {
if (count > 0) {
+ final Object[] items = this.items;
final int putIndex = this.putIndex;
int i = takeIndex;
do {
@@ -474,7 +458,8 @@ public class ArrayBlockingQueue<E> extends AbstractQueue<E>
removeAt(i);
return true;
}
- } while ((i = inc(i)) != putIndex);
+ if (++i == items.length) i = 0;
+ } while (i != putIndex);
}
return false;
} finally {
@@ -492,17 +477,18 @@ public class ArrayBlockingQueue<E> extends AbstractQueue<E>
*/
public boolean contains(Object o) {
if (o == null) return false;
- final Object[] items = this.items;
final ReentrantLock lock = this.lock;
lock.lock();
try {
if (count > 0) {
+ final Object[] items = this.items;
final int putIndex = this.putIndex;
int i = takeIndex;
do {
if (o.equals(items[i]))
return true;
- } while ((i = inc(i)) != putIndex);
+ if (++i == items.length) i = 0;
+ } while (i != putIndex);
}
return false;
} finally {
@@ -524,19 +510,14 @@ public class ArrayBlockingQueue<E> extends AbstractQueue<E>
* @return an array containing all of the elements in this queue
*/
public Object[] toArray() {
- final Object[] items = this.items;
final ReentrantLock lock = this.lock;
lock.lock();
try {
- final int count = this.count;
- Object[] a = new Object[count];
- int n = items.length - takeIndex;
- if (count <= n) {
- System.arraycopy(items, takeIndex, a, 0, count);
- } else {
- System.arraycopy(items, takeIndex, a, 0, n);
- System.arraycopy(items, 0, a, n, count - n);
- }
+ final Object[] items = this.items;
+ final int end = takeIndex + count;
+ final Object[] a = Arrays.copyOfRange(items, takeIndex, end);
+ if (end != putIndex)
+ System.arraycopy(items, 0, a, items.length - takeIndex, putIndex);
return a;
} finally {
lock.unlock();
@@ -564,7 +545,7 @@ public class ArrayBlockingQueue<E> extends AbstractQueue<E>
* The following code can be used to dump the queue into a newly
* allocated array of {@code String}:
*
- * <pre> {@code String[] y = x.toArray(new String[0]);}</pre>
+ * <pre> {@code String[] y = x.toArray(new String[0]);}</pre>
*
* Note that {@code toArray(new Object[0])} is identical in function to
* {@code toArray()}.
@@ -580,24 +561,22 @@ public class ArrayBlockingQueue<E> extends AbstractQueue<E>
*/
@SuppressWarnings("unchecked")
public <T> T[] toArray(T[] a) {
- final Object[] items = this.items;
final ReentrantLock lock = this.lock;
lock.lock();
try {
+ final Object[] items = this.items;
final int count = this.count;
- final int len = a.length;
- if (len < count)
- a = (T[])java.lang.reflect.Array.newInstance(
- a.getClass().getComponentType(), count);
- int n = items.length - takeIndex;
- if (count <= n)
- System.arraycopy(items, takeIndex, a, 0, count);
- else {
- System.arraycopy(items, takeIndex, a, 0, n);
- System.arraycopy(items, 0, a, n, count - n);
+ final int firstLeg = Math.min(items.length - takeIndex, count);
+ if (a.length < count) {
+ a = (T[]) Arrays.copyOfRange(items, takeIndex, takeIndex + count,
+ a.getClass());
+ } else {
+ System.arraycopy(items, takeIndex, a, 0, firstLeg);
+ if (a.length > count)
+ a[count] = null;
}
- if (len > count)
- a[count] = null;
+ if (firstLeg < count)
+ System.arraycopy(items, 0, a, firstLeg, putIndex);
return a;
} finally {
lock.unlock();
@@ -612,14 +591,16 @@ public class ArrayBlockingQueue<E> extends AbstractQueue<E>
if (k == 0)
return "[]";
+ final Object[] items = this.items;
StringBuilder sb = new StringBuilder();
sb.append('[');
- for (int i = takeIndex; ; i = inc(i)) {
+ for (int i = takeIndex; ; ) {
Object e = items[i];
sb.append(e == this ? "(this Collection)" : e);
if (--k == 0)
return sb.append(']').toString();
sb.append(',').append(' ');
+ if (++i == items.length) i = 0;
}
} finally {
lock.unlock();
@@ -641,7 +622,8 @@ public class ArrayBlockingQueue<E> extends AbstractQueue<E>
int i = takeIndex;
do {
items[i] = null;
- } while ((i = inc(i)) != putIndex);
+ if (++i == items.length) i = 0;
+ } while (i != putIndex);
takeIndex = putIndex;
count = 0;
if (itrs != null)
@@ -671,7 +653,7 @@ public class ArrayBlockingQueue<E> extends AbstractQueue<E>
* @throws IllegalArgumentException {@inheritDoc}
*/
public int drainTo(Collection<? super E> c, int maxElements) {
- checkNotNull(c);
+ if (c == null) throw new NullPointerException();
if (c == this)
throw new IllegalArgumentException();
if (maxElements <= 0)
@@ -689,7 +671,7 @@ public class ArrayBlockingQueue<E> extends AbstractQueue<E>
E x = (E) items[take];
c.add(x);
items[take] = null;
- take = inc(take);
+ if (++take == items.length) take = 0;
i++;
}
return n;
@@ -717,12 +699,8 @@ public class ArrayBlockingQueue<E> extends AbstractQueue<E>
* Returns an iterator over the elements in this queue in proper sequence.
* The elements will be returned in order from first (head) to last (tail).
*
- * <p>The returned iterator is a "weakly consistent" iterator that
- * will never throw {@link java.util.ConcurrentModificationException
- * ConcurrentModificationException}, and guarantees to traverse
- * elements as they existed upon construction of the iterator, and
- * may (but is not guaranteed to) reflect any modifications
- * subsequent to construction.
+ * <p>The returned iterator is
+ * <a href="package-summary.html#Weakly"><i>weakly consistent</i></a>.
*
* @return an iterator over the elements in this queue in proper sequence
*/
@@ -796,13 +774,13 @@ public class ArrayBlockingQueue<E> extends AbstractQueue<E>
}
/** Incremented whenever takeIndex wraps around to 0 */
- int cycles = 0;
+ int cycles;
/** Linked list of weak iterator references */
private Node head;
/** Used to expunge stale iterators */
- private Node sweeper = null;
+ private Node sweeper;
private static final int SHORT_SWEEP_PROBES = 4;
private static final int LONG_SWEEP_PROBES = 16;
@@ -910,7 +888,7 @@ public class ArrayBlockingQueue<E> extends AbstractQueue<E>
}
/**
- * Called whenever an interior remove (not at takeIndex) occured.
+ * Called whenever an interior remove (not at takeIndex) occurred.
*
* Notifies all iterators, and expunges any that are now stale.
*/
@@ -1059,9 +1037,8 @@ public class ArrayBlockingQueue<E> extends AbstractQueue<E>
private int incCursor(int index) {
// assert lock.getHoldCount() == 1;
- index = inc(index);
- if (index == putIndex)
- index = NONE;
+ if (++index == items.length) index = 0;
+ if (index == putIndex) index = NONE;
return index;
}
@@ -1268,7 +1245,7 @@ public class ArrayBlockingQueue<E> extends AbstractQueue<E>
}
/**
- * Called whenever an interior remove (not at takeIndex) occured.
+ * Called whenever an interior remove (not at takeIndex) occurred.
*
* @return true if this iterator should be unlinked from itrs
*/
@@ -1277,17 +1254,18 @@ public class ArrayBlockingQueue<E> extends AbstractQueue<E>
if (isDetached())
return true;
- final int cycles = itrs.cycles;
final int takeIndex = ArrayBlockingQueue.this.takeIndex;
- final int prevCycles = this.prevCycles;
final int prevTakeIndex = this.prevTakeIndex;
final int len = items.length;
- int cycleDiff = cycles - prevCycles;
- if (removedIndex < takeIndex)
- cycleDiff++;
+ // distance from prevTakeIndex to removedIndex
final int removedDistance =
- (cycleDiff * len) + (removedIndex - prevTakeIndex);
- // assert removedDistance >= 0;
+ len * (itrs.cycles - this.prevCycles
+ + ((removedIndex < takeIndex) ? 1 : 0))
+ + (removedIndex - prevTakeIndex);
+ // assert itrs.cycles - this.prevCycles >= 0;
+ // assert itrs.cycles - this.prevCycles <= 1;
+ // assert removedDistance > 0;
+ // assert removedIndex != takeIndex;
int cursor = this.cursor;
if (cursor >= 0) {
int x = distance(cursor, prevTakeIndex, len);
@@ -1316,7 +1294,7 @@ public class ArrayBlockingQueue<E> extends AbstractQueue<E>
else if (x > removedDistance)
this.nextIndex = nextIndex = dec(nextIndex);
}
- else if (cursor < 0 && nextIndex < 0 && lastRet < 0) {
+ if (cursor < 0 && nextIndex < 0 && lastRet < 0) {
this.prevTakeIndex = DETACHED;
return true;
}
@@ -1354,4 +1332,5 @@ public class ArrayBlockingQueue<E> extends AbstractQueue<E>
// "remainingCapacity()=" + remainingCapacity());
// }
}
+
}
diff --git a/luni/src/main/java/java/util/concurrent/BlockingDeque.java b/luni/src/main/java/java/util/concurrent/BlockingDeque.java
index 8a393ba..b1437cc 100644
--- a/luni/src/main/java/java/util/concurrent/BlockingDeque.java
+++ b/luni/src/main/java/java/util/concurrent/BlockingDeque.java
@@ -5,6 +5,7 @@
*/
package java.util.concurrent;
+
import java.util.*;
/**
@@ -23,6 +24,7 @@ import java.util.*;
*
* <p>
* <table BORDER CELLPADDING=3 CELLSPACING=1>
+ * <caption>Summary of BlockingDeque methods</caption>
* <tr>
* <td ALIGN=CENTER COLSPAN = 5> <b>First Element (Head)</b></td>
* </tr>
@@ -98,6 +100,7 @@ import java.util.*;
*
* <p>
* <table BORDER CELLPADDING=3 CELLSPACING=1>
+ * <caption>Comparison of BlockingQueue and BlockingDeque methods</caption>
* <tr>
* <td ALIGN=CENTER> <b>{@code BlockingQueue} Method</b></td>
* <td ALIGN=CENTER> <b>Equivalent {@code BlockingDeque} Method</b></td>
@@ -606,9 +609,10 @@ public interface BlockingDeque<E> extends BlockingQueue<E>, Deque<E> {
// *** Stack methods ***
/**
- * Pushes an element onto the stack represented by this deque. In other
- * words, inserts the element at the front of this deque unless it would
- * violate capacity restrictions.
+ * Pushes an element onto the stack represented by this deque (in other
+ * words, at the head of this deque) if it is possible to do so
+ * immediately without violating capacity restrictions, throwing an
+ * {@code IllegalStateException} if no space is currently available.
*
* <p>This method is equivalent to {@link #addFirst(Object) addFirst}.
*
diff --git a/luni/src/main/java/java/util/concurrent/BlockingQueue.java b/luni/src/main/java/java/util/concurrent/BlockingQueue.java
index cc6d541..33d83b7 100644
--- a/luni/src/main/java/java/util/concurrent/BlockingQueue.java
+++ b/luni/src/main/java/java/util/concurrent/BlockingQueue.java
@@ -30,6 +30,7 @@ import java.util.Queue;
*
* <p>
* <table BORDER CELLPADDING=3 CELLSPACING=1>
+ * <caption>Summary of BlockingQueue methods</caption>
* <tr>
* <td></td>
* <td ALIGN=CENTER><em>Throws exception</em></td>
diff --git a/luni/src/main/java/java/util/concurrent/ConcurrentHashMap.java b/luni/src/main/java/java/util/concurrent/ConcurrentHashMap.java
index ea3b1e9..3ed54cf 100644
--- a/luni/src/main/java/java/util/concurrent/ConcurrentHashMap.java
+++ b/luni/src/main/java/java/util/concurrent/ConcurrentHashMap.java
@@ -10,9 +10,9 @@ import java.io.ObjectStreamField;
import java.io.Serializable;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
+import java.util.AbstractMap;
import java.util.Arrays;
import java.util.Collection;
-import java.util.Comparator;
import java.util.ConcurrentModificationException;
import java.util.Enumeration;
import java.util.HashMap;
@@ -22,7 +22,6 @@ import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Set;
import java.util.concurrent.ConcurrentMap;
-import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.LockSupport;
import java.util.concurrent.locks.ReentrantLock;
@@ -99,7 +98,9 @@ import java.util.concurrent.locks.ReentrantLock;
* @param <K> the type of keys maintained by this map
* @param <V> the type of mapped values
*/
-public class ConcurrentHashMap<K,V> extends java.util.AbstractMap<K,V>
+// android-note: removed documentation about hidden newKeySet and newKeySet(int) APIs.
+// android-note: Added "extends AbstractMap<K, V>.
+public class ConcurrentHashMap<K,V> extends AbstractMap<K, V>
implements ConcurrentMap<K,V>, Serializable {
private static final long serialVersionUID = 7249069246763182397L;
@@ -208,14 +209,15 @@ public class ConcurrentHashMap<K,V> extends java.util.AbstractMap<K,V>
* The table is resized when occupancy exceeds a percentage
* threshold (nominally, 0.75, but see below). Any thread
* noticing an overfull bin may assist in resizing after the
- * initiating thread allocates and sets up the replacement
- * array. However, rather than stalling, these other threads may
- * proceed with insertions etc. The use of TreeBins shields us
- * from the worst case effects of overfilling while resizes are in
+ * initiating thread allocates and sets up the replacement array.
+ * However, rather than stalling, these other threads may proceed
+ * with insertions etc. The use of TreeBins shields us from the
+ * worst case effects of overfilling while resizes are in
* progress. Resizing proceeds by transferring bins, one by one,
- * from the table to the next table. To enable concurrency, the
- * next table must be (incrementally) prefilled with place-holders
- * serving as reverse forwarders to the old table. Because we are
+ * from the table to the next table. However, threads claim small
+ * blocks of indices to transfer (via field transferIndex) before
+ * doing so, reducing contention. A generation stamp in field
+ * sizeCtl ensures that resizings do not overlap. Because we are
* using power-of-two expansion, the elements from each bin must
* either stay at same index, or move with a power of two
* offset. We eliminate unnecessary node creation by catching
@@ -236,13 +238,19 @@ public class ConcurrentHashMap<K,V> extends java.util.AbstractMap<K,V>
* locks, average aggregate waits become shorter as resizing
* progresses. The transfer operation must also ensure that all
* accessible bins in both the old and new table are usable by any
- * traversal. This is arranged by proceeding from the last bin
- * (table.length - 1) up towards the first. Upon seeing a
- * forwarding node, traversals (see class Traverser) arrange to
- * move to the new table without revisiting nodes. However, to
- * ensure that no intervening nodes are skipped, bin splitting can
- * only begin after the associated reverse-forwarders are in
- * place.
+ * traversal. This is arranged in part by proceeding from the
+ * last bin (table.length - 1) up towards the first. Upon seeing
+ * a forwarding node, traversals (see class Traverser) arrange to
+ * move to the new table without revisiting nodes. To ensure that
+ * no intervening nodes are skipped even when moved out of order,
+ * a stack (see class TableStack) is created on first encounter of
+ * a forwarding node during a traversal, to maintain its place if
+ * later processing the current table. The need for these
+ * save/restore mechanics is relatively rare, but when one
+ * forwarding node is encountered, typically many more will be.
+ * So Traversers use a simple caching scheme to avoid creating so
+ * many new TableStack nodes. (Thanks to Peter Levart for
+ * suggesting use of a stack here.)
*
* The traversal scheme also applies to partial traversals of
* ranges of bins (via an alternate Traverser constructor)
@@ -274,16 +282,18 @@ public class ConcurrentHashMap<K,V> extends java.util.AbstractMap<K,V>
* related operations (which is the main reason we cannot use
* existing collections such as TreeMaps). TreeBins contain
* Comparable elements, but may contain others, as well as
- * elements that are Comparable but not necessarily Comparable
- * for the same T, so we cannot invoke compareTo among them. To
- * handle this, the tree is ordered primarily by hash value, then
- * by Comparable.compareTo order if applicable. On lookup at a
- * node, if elements are not comparable or compare as 0 then both
- * left and right children may need to be searched in the case of
- * tied hash values. (This corresponds to the full list search
- * that would be necessary if all elements were non-Comparable and
- * had tied hashes.) The red-black balancing code is updated from
- * pre-jdk-collections
+ * elements that are Comparable but not necessarily Comparable for
+ * the same T, so we cannot invoke compareTo among them. To handle
+ * this, the tree is ordered primarily by hash value, then by
+ * Comparable.compareTo order if applicable. On lookup at a node,
+ * if elements are not comparable or compare as 0 then both left
+ * and right children may need to be searched in the case of tied
+ * hash values. (This corresponds to the full list search that
+ * would be necessary if all elements were non-Comparable and had
+ * tied hashes.) On insertion, to keep a total ordering (or as
+ * close as is required here) across rebalancings, we compare
+ * classes and identityHashCodes as tie-breakers. The red-black
+ * balancing code is updated from pre-jdk-collections
* (http://gee.cs.oswego.edu/dl/classes/collections/RBCell.java)
* based in turn on Cormen, Leiserson, and Rivest "Introduction to
* Algorithms" (CLR).
@@ -313,6 +323,10 @@ public class ConcurrentHashMap<K,V> extends java.util.AbstractMap<K,V>
* unused "Segment" class that is instantiated in minimal form
* only when serializing.
*
+ * Also, solely for compatibility with previous versions of this
+ * class, it extends AbstractMap, even though all of its methods
+ * are overridden, so it is just useless baggage.
+ *
* This file is organized to make things a little easier to follow
* while reading than they might otherwise: First the main static
* declarations and utilities, then fields, then main public
@@ -321,6 +335,7 @@ public class ConcurrentHashMap<K,V> extends java.util.AbstractMap<K,V>
* bulk operations.
*/
+
/* ---------------- Constants -------------- */
/**
@@ -393,6 +408,23 @@ public class ConcurrentHashMap<K,V> extends java.util.AbstractMap<K,V>
*/
private static final int MIN_TRANSFER_STRIDE = 16;
+ /**
+ * The number of bits used for generation stamp in sizeCtl.
+ * Must be at least 6 for 32bit arrays.
+ */
+ private static int RESIZE_STAMP_BITS = 16;
+
+ /**
+ * The maximum number of threads that can help resize.
+ * Must fit in 32 - RESIZE_STAMP_BITS bits.
+ */
+ private static final int MAX_RESIZERS = (1 << (32 - RESIZE_STAMP_BITS)) - 1;
+
+ /**
+ * The bit shift for recording size stamp in sizeCtl.
+ */
+ private static final int RESIZE_STAMP_SHIFT = 32 - RESIZE_STAMP_BITS;
+
/*
* Encodings for Node hash fields. See above for explanation.
*/
@@ -504,7 +536,6 @@ public class ConcurrentHashMap<K,V> extends java.util.AbstractMap<K,V>
return (n < 0) ? 1 : (n >= MAXIMUM_CAPACITY) ? MAXIMUM_CAPACITY : n + 1;
}
-
/**
* Returns x's Class if it is of the form "class C implements
* Comparable<C>", else null.
@@ -605,11 +636,6 @@ public class ConcurrentHashMap<K,V> extends java.util.AbstractMap<K,V>
private transient volatile int transferIndex;
/**
- * The least available table index to split while resizing.
- */
- private transient volatile int transferOrigin;
-
- /**
* Spinlock (locked via CAS) used when resizing and/or creating CounterCells.
*/
private transient volatile int cellsBusy;
@@ -1035,8 +1061,8 @@ public class ConcurrentHashMap<K,V> extends java.util.AbstractMap<K,V>
* reflect any modifications subsequent to construction.
*
* @return the set view
- *
*/
+ // android-note : changed KeySetView<K,V> to Set<K> to maintain API compatibility.
public Set<K> keySet() {
KeySetView<K,V> ks;
return (ks = keySet) != null ? ks : (keySet = new KeySetView<K,V>(this, null));
@@ -1209,9 +1235,10 @@ public class ConcurrentHashMap<K,V> extends java.util.AbstractMap<K,V>
new Segment<?,?>[DEFAULT_CONCURRENCY_LEVEL];
for (int i = 0; i < segments.length; ++i)
segments[i] = new Segment<K,V>(LOAD_FACTOR);
- s.putFields().put("segments", segments);
- s.putFields().put("segmentShift", segmentShift);
- s.putFields().put("segmentMask", segmentMask);
+ java.io.ObjectOutputStream.PutField streamFields = s.putFields();
+ streamFields.put("segments", segments);
+ streamFields.put("segmentShift", segmentShift);
+ streamFields.put("segmentMask", segmentMask);
s.writeFields();
Node<K,V>[] t;
@@ -1264,8 +1291,8 @@ public class ConcurrentHashMap<K,V> extends java.util.AbstractMap<K,V>
int sz = (int)size;
n = tableSizeFor(sz + (sz >>> 1) + 1);
}
- @SuppressWarnings({"rawtypes","unchecked"})
- Node<K,V>[] tab = (Node<K,V>[])new Node[n];
+ @SuppressWarnings("unchecked")
+ Node<K,V>[] tab = (Node<K,V>[])new Node<?,?>[n];
int mask = n - 1;
long added = 0L;
while (p != null) {
@@ -1377,9 +1404,13 @@ public class ConcurrentHashMap<K,V> extends java.util.AbstractMap<K,V>
/**
* Legacy method testing if some key maps into the specified value
- * in this table. This method is identical in functionality to
+ * in this table.
+ *
+ * This method is identical in functionality to
* {@link #containsValue(Object)}, and exists solely to ensure
- * full compatibility with class {@link java.util.Hashtable}.
+ * full compatibility with class {@link java.util.Hashtable},
+ * which supported this method prior to introduction of the
+ * Java Collections framework.
*
* @param value a value to search for
* @return {@code true} if and only if some key maps to the
@@ -1388,6 +1419,7 @@ public class ConcurrentHashMap<K,V> extends java.util.AbstractMap<K,V>
* {@code false} otherwise
* @throws NullPointerException if the specified value is null
*/
+ // android-note : removed @deprecated tag from javadoc.
public boolean contains(Object value) {
// BEGIN android-note
// removed deprecation
@@ -1442,6 +1474,7 @@ public class ConcurrentHashMap<K,V> extends java.util.AbstractMap<K,V>
* Creates a new {@link Set} backed by a ConcurrentHashMap
* from the given type to {@code Boolean.TRUE}.
*
+ * @param <K> the element type of the returned set
* @return the new set
* @since 1.8
*
@@ -1458,9 +1491,10 @@ public class ConcurrentHashMap<K,V> extends java.util.AbstractMap<K,V>
*
* @param initialCapacity The implementation performs internal
* sizing to accommodate this many elements.
+ * @param <K> the element type of the returned set
+ * @return the new set
* @throws IllegalArgumentException if the initial capacity of
* elements is negative
- * @return the new set
* @since 1.8
*
* @hide
@@ -1483,7 +1517,7 @@ public class ConcurrentHashMap<K,V> extends java.util.AbstractMap<K,V>
*
* @hide
*/
- public Set<K> keySet(V mappedValue) {
+ public KeySetView<K,V> keySet(V mappedValue) {
if (mappedValue == null)
throw new NullPointerException();
return new KeySetView<K,V>(this, mappedValue);
@@ -1535,6 +1569,14 @@ public class ConcurrentHashMap<K,V> extends java.util.AbstractMap<K,V>
/* ---------------- Table Initialization and Resizing -------------- */
/**
+ * Returns the stamp bits for resizing a table of size n.
+ * Must be negative when shifted left by RESIZE_STAMP_SHIFT.
+ */
+ static final int resizeStamp(int n) {
+ return Integer.numberOfLeadingZeros(n) | (1 << (RESIZE_STAMP_BITS - 1));
+ }
+
+ /**
* Initializes table, using the size recorded in sizeCtl.
*/
private final Node<K,V>[] initTable() {
@@ -1546,8 +1588,8 @@ public class ConcurrentHashMap<K,V> extends java.util.AbstractMap<K,V>
try {
if ((tab = table) == null || tab.length == 0) {
int n = (sc > 0) ? sc : DEFAULT_CAPACITY;
- @SuppressWarnings({"rawtypes","unchecked"})
- Node<K,V>[] nt = (Node<K,V>[])new Node[n];
+ @SuppressWarnings("unchecked")
+ Node<K,V>[] nt = (Node<K,V>[])new Node<?,?>[n];
table = tab = nt;
sc = n - (n >>> 2);
}
@@ -1589,17 +1631,20 @@ public class ConcurrentHashMap<K,V> extends java.util.AbstractMap<K,V>
s = sumCount();
}
if (check >= 0) {
- Node<K,V>[] tab, nt; int sc;
+ Node<K,V>[] tab, nt; int n, sc;
while (s >= (long)(sc = sizeCtl) && (tab = table) != null &&
- tab.length < MAXIMUM_CAPACITY) {
+ (n = tab.length) < MAXIMUM_CAPACITY) {
+ int rs = resizeStamp(n);
if (sc < 0) {
- if (sc == -1 || transferIndex <= transferOrigin ||
- (nt = nextTable) == null)
+ if ((sc >>> RESIZE_STAMP_SHIFT) != rs || sc == rs + 1 ||
+ sc == rs + MAX_RESIZERS || (nt = nextTable) == null ||
+ transferIndex <= 0)
break;
- if (U.compareAndSwapInt(this, SIZECTL, sc, sc - 1))
+ if (U.compareAndSwapInt(this, SIZECTL, sc, sc + 1))
transfer(tab, nt);
}
- else if (U.compareAndSwapInt(this, SIZECTL, sc, -2))
+ else if (U.compareAndSwapInt(this, SIZECTL, sc,
+ (rs << RESIZE_STAMP_SHIFT) + 2))
transfer(tab, null);
s = sumCount();
}
@@ -1611,12 +1656,19 @@ public class ConcurrentHashMap<K,V> extends java.util.AbstractMap<K,V>
*/
final Node<K,V>[] helpTransfer(Node<K,V>[] tab, Node<K,V> f) {
Node<K,V>[] nextTab; int sc;
- if ((f instanceof ForwardingNode) &&
+ if (tab != null && (f instanceof ForwardingNode) &&
(nextTab = ((ForwardingNode<K,V>)f).nextTable) != null) {
- if (nextTab == nextTable && tab == table &&
- transferIndex > transferOrigin && (sc = sizeCtl) < -1 &&
- U.compareAndSwapInt(this, SIZECTL, sc, sc - 1))
- transfer(tab, nextTab);
+ int rs = resizeStamp(tab.length);
+ while (nextTab == nextTable && table == tab &&
+ (sc = sizeCtl) < 0) {
+ if ((sc >>> RESIZE_STAMP_SHIFT) != rs || sc == rs + 1 ||
+ sc == rs + MAX_RESIZERS || transferIndex <= 0)
+ break;
+ if (U.compareAndSwapInt(this, SIZECTL, sc, sc + 1)) {
+ transfer(tab, nextTab);
+ break;
+ }
+ }
return nextTab;
}
return table;
@@ -1638,8 +1690,8 @@ public class ConcurrentHashMap<K,V> extends java.util.AbstractMap<K,V>
if (U.compareAndSwapInt(this, SIZECTL, sc, -1)) {
try {
if (table == tab) {
- @SuppressWarnings({"rawtypes","unchecked"})
- Node<K,V>[] nt = (Node<K,V>[])new Node[n];
+ @SuppressWarnings("unchecked")
+ Node<K,V>[] nt = (Node<K,V>[])new Node<?,?>[n];
table = nt;
sc = n - (n >>> 2);
}
@@ -1650,9 +1702,21 @@ public class ConcurrentHashMap<K,V> extends java.util.AbstractMap<K,V>
}
else if (c <= sc || n >= MAXIMUM_CAPACITY)
break;
- else if (tab == table &&
- U.compareAndSwapInt(this, SIZECTL, sc, -2))
- transfer(tab, null);
+ else if (tab == table) {
+ int rs = resizeStamp(n);
+ if (sc < 0) {
+ Node<K,V>[] nt;
+ if ((sc >>> RESIZE_STAMP_SHIFT) != rs || sc == rs + 1 ||
+ sc == rs + MAX_RESIZERS || (nt = nextTable) == null ||
+ transferIndex <= 0)
+ break;
+ if (U.compareAndSwapInt(this, SIZECTL, sc, sc + 1))
+ transfer(tab, nt);
+ }
+ else if (U.compareAndSwapInt(this, SIZECTL, sc,
+ (rs << RESIZE_STAMP_SHIFT) + 2))
+ transfer(tab, null);
+ }
}
}
@@ -1666,35 +1730,27 @@ public class ConcurrentHashMap<K,V> extends java.util.AbstractMap<K,V>
stride = MIN_TRANSFER_STRIDE; // subdivide range
if (nextTab == null) { // initiating
try {
- @SuppressWarnings({"rawtypes","unchecked"})
- Node<K,V>[] nt = (Node<K,V>[])new Node[n << 1];
+ @SuppressWarnings("unchecked")
+ Node<K,V>[] nt = (Node<K,V>[])new Node<?,?>[n << 1];
nextTab = nt;
} catch (Throwable ex) { // try to cope with OOME
sizeCtl = Integer.MAX_VALUE;
return;
}
nextTable = nextTab;
- transferOrigin = n;
transferIndex = n;
- ForwardingNode<K,V> rev = new ForwardingNode<K,V>(tab);
- for (int k = n; k > 0;) { // progressively reveal ready slots
- int nextk = (k > stride) ? k - stride : 0;
- for (int m = nextk; m < k; ++m)
- nextTab[m] = rev;
- for (int m = n + nextk; m < n + k; ++m)
- nextTab[m] = rev;
- U.putOrderedInt(this, TRANSFERORIGIN, k = nextk);
- }
}
int nextn = nextTab.length;
ForwardingNode<K,V> fwd = new ForwardingNode<K,V>(nextTab);
boolean advance = true;
+ boolean finishing = false; // to ensure sweep before committing nextTab
for (int i = 0, bound = 0;;) {
- int nextIndex, nextBound, fh; Node<K,V> f;
+ Node<K,V> f; int fh;
while (advance) {
- if (--i >= bound)
+ int nextIndex, nextBound;
+ if (--i >= bound || finishing)
advance = false;
- else if ((nextIndex = transferIndex) <= transferOrigin) {
+ else if ((nextIndex = transferIndex) <= 0) {
i = -1;
advance = false;
}
@@ -1708,24 +1764,22 @@ public class ConcurrentHashMap<K,V> extends java.util.AbstractMap<K,V>
}
}
if (i < 0 || i >= n || i + n >= nextn) {
- for (int sc;;) {
- if (U.compareAndSwapInt(this, SIZECTL, sc = sizeCtl, ++sc)) {
- if (sc == -1) {
- nextTable = null;
- table = nextTab;
- sizeCtl = (n << 1) - (n >>> 1);
- }
- return;
- }
+ int sc;
+ if (finishing) {
+ nextTable = null;
+ table = nextTab;
+ sizeCtl = (n << 1) - (n >>> 1);
+ return;
}
- }
- else if ((f = tabAt(tab, i)) == null) {
- if (casTabAt(tab, i, null, fwd)) {
- setTabAt(nextTab, i, null);
- setTabAt(nextTab, i + n, null);
- advance = true;
+ if (U.compareAndSwapInt(this, SIZECTL, sc = sizeCtl, sc - 1)) {
+ if ((sc - 2) != resizeStamp(n) << RESIZE_STAMP_SHIFT)
+ return;
+ finishing = advance = true;
+ i = n; // recheck before commit
}
}
+ else if ((f = tabAt(tab, i)) == null)
+ advance = casTabAt(tab, i, null, fwd);
else if ((fh = f.hash) == MOVED)
advance = true; // already processed
else {
@@ -1757,6 +1811,10 @@ public class ConcurrentHashMap<K,V> extends java.util.AbstractMap<K,V>
else
hn = new Node<K,V>(ph, pk, pv, hn);
}
+ setTabAt(nextTab, i, ln);
+ setTabAt(nextTab, i + n, hn);
+ setTabAt(tab, i, fwd);
+ advance = true;
}
else if (f instanceof TreeBin) {
TreeBin<K,V> t = (TreeBin<K,V>)f;
@@ -1788,13 +1846,11 @@ public class ConcurrentHashMap<K,V> extends java.util.AbstractMap<K,V>
(hc != 0) ? new TreeBin<K,V>(lo) : t;
hn = (hc <= UNTREEIFY_THRESHOLD) ? untreeify(hi) :
(lc != 0) ? new TreeBin<K,V>(hi) : t;
+ setTabAt(nextTab, i, ln);
+ setTabAt(nextTab, i + n, hn);
+ setTabAt(tab, i, fwd);
+ advance = true;
}
- else
- ln = hn = null;
- setTabAt(nextTab, i, ln);
- setTabAt(nextTab, i + n, hn);
- setTabAt(tab, i, fwd);
- advance = true;
}
}
}
@@ -1810,12 +1866,9 @@ public class ConcurrentHashMap<K,V> extends java.util.AbstractMap<K,V>
private final void treeifyBin(Node<K,V>[] tab, int index) {
Node<K,V> b; int n, sc;
if (tab != null) {
- if ((n = tab.length) < MIN_TREEIFY_CAPACITY) {
- if (tab == table && (sc = sizeCtl) >= 0 &&
- U.compareAndSwapInt(this, SIZECTL, sc, -2))
- transfer(tab, null);
- }
- else if ((b = tabAt(tab, index)) != null) {
+ if ((n = tab.length) < MIN_TREEIFY_CAPACITY)
+ tryPresize(n << 1);
+ else if ((b = tabAt(tab, index)) != null && b.hash >= 0) {
synchronized (b) {
if (tabAt(tab, index) == b) {
TreeNode<K,V> hd = null, tl = null;
@@ -1881,7 +1934,7 @@ public class ConcurrentHashMap<K,V> extends java.util.AbstractMap<K,V>
final TreeNode<K,V> findTreeNode(int h, Object k, Class<?> kc) {
if (k != null) {
TreeNode<K,V> p = this;
- do {
+ do {
int ph, dir; K pk; TreeNode<K,V> q;
TreeNode<K,V> pl = p.left, pr = p.right;
if ((ph = p.hash) > h)
@@ -1890,25 +1943,25 @@ public class ConcurrentHashMap<K,V> extends java.util.AbstractMap<K,V>
p = pr;
else if ((pk = p.key) == k || (pk != null && k.equals(pk)))
return p;
- else if (pl == null && pr == null)
- break;
+ else if (pl == null)
+ p = pr;
+ else if (pr == null)
+ p = pl;
else if ((kc != null ||
(kc = comparableClassFor(k)) != null) &&
(dir = compareComparables(kc, k, pk)) != 0)
p = (dir < 0) ? pl : pr;
- else if (pl == null)
- p = pr;
- else if (pr == null ||
- (q = pr.findTreeNode(h, k, kc)) == null)
- p = pl;
- else
+ else if ((q = pr.findTreeNode(h, k, kc)) != null)
return q;
+ else
+ p = pl;
} while (p != null);
}
return null;
}
}
+
/* ---------------- TreeBins -------------- */
/**
@@ -1929,6 +1982,23 @@ public class ConcurrentHashMap<K,V> extends java.util.AbstractMap<K,V>
static final int READER = 4; // increment value for setting read lock
/**
+ * Tie-breaking utility for ordering insertions when equal
+ * hashCodes and non-comparable. We don't require a total
+ * order, just a consistent insertion rule to maintain
+ * equivalence across rebalancings. Tie-breaking further than
+ * necessary simplifies testing a bit.
+ */
+ static int tieBreakOrder(Object a, Object b) {
+ int d;
+ if (a == null || b == null ||
+ (d = a.getClass().getName().
+ compareTo(b.getClass().getName())) == 0)
+ d = (System.identityHashCode(a) <= System.identityHashCode(b) ?
+ -1 : 1);
+ return d;
+ }
+
+ /**
* Creates bin with initial set of nodes headed by b.
*/
TreeBin(TreeNode<K,V> b) {
@@ -1944,21 +2014,21 @@ public class ConcurrentHashMap<K,V> extends java.util.AbstractMap<K,V>
r = x;
}
else {
- Object key = x.key;
- int hash = x.hash;
+ K k = x.key;
+ int h = x.hash;
Class<?> kc = null;
for (TreeNode<K,V> p = r;;) {
int dir, ph;
- if ((ph = p.hash) > hash)
+ K pk = p.key;
+ if ((ph = p.hash) > h)
dir = -1;
- else if (ph < hash)
+ else if (ph < h)
dir = 1;
- else if ((kc != null ||
- (kc = comparableClassFor(key)) != null))
- dir = compareComparables(kc, key, p.key);
- else
- dir = 0;
- TreeNode<K,V> xp = p;
+ else if ((kc == null &&
+ (kc = comparableClassFor(k)) == null) ||
+ (dir = compareComparables(kc, k, pk)) == 0)
+ dir = tieBreakOrder(k, pk);
+ TreeNode<K,V> xp = p;
if ((p = (dir <= 0) ? p.left : p.right) == null) {
x.parent = xp;
if (dir <= 0)
@@ -1972,6 +2042,7 @@ public class ConcurrentHashMap<K,V> extends java.util.AbstractMap<K,V>
}
}
this.root = r;
+ assert checkInvariants(root);
}
/**
@@ -1995,7 +2066,7 @@ public class ConcurrentHashMap<K,V> extends java.util.AbstractMap<K,V>
private final void contendedLock() {
boolean waiting = false;
for (int s;;) {
- if (((s = lockState) & WRITER) == 0) {
+ if (((s = lockState) & ~WAITER) == 0) {
if (U.compareAndSwapInt(this, LOCKSTATE, s, WRITER)) {
if (waiting)
waiter = null;
@@ -2020,12 +2091,13 @@ public class ConcurrentHashMap<K,V> extends java.util.AbstractMap<K,V>
*/
final Node<K,V> find(int h, Object k) {
if (k != null) {
- for (Node<K,V> e = first; e != null; e = e.next) {
+ for (Node<K,V> e = first; e != null; ) {
int s; K ek;
if (((s = lockState) & (WAITER|WRITER)) != 0) {
if (e.hash == h &&
((ek = e.key) == k || (ek != null && k.equals(ek))))
return e;
+ e = e.next;
}
else if (U.compareAndSwapInt(this, LOCKSTATE, s,
s + READER)) {
@@ -2054,10 +2126,15 @@ public class ConcurrentHashMap<K,V> extends java.util.AbstractMap<K,V>
* Finds or adds a node.
* @return null if added
*/
+ /**
+ * Finds or adds a node.
+ * @return null if added
+ */
final TreeNode<K,V> putTreeVal(int h, K k, V v) {
Class<?> kc = null;
+ boolean searched = false;
for (TreeNode<K,V> p = root;;) {
- int dir, ph; K pk; TreeNode<K,V> q, pr;
+ int dir, ph; K pk;
if (p == null) {
first = root = new TreeNode<K,V>(h, k, v, null, null);
break;
@@ -2071,21 +2148,25 @@ public class ConcurrentHashMap<K,V> extends java.util.AbstractMap<K,V>
else if ((kc == null &&
(kc = comparableClassFor(k)) == null) ||
(dir = compareComparables(kc, k, pk)) == 0) {
- if (p.left == null)
- dir = 1;
- else if ((pr = p.right) == null ||
- (q = pr.findTreeNode(h, k, kc)) == null)
- dir = -1;
- else
- return q;
+ if (!searched) {
+ TreeNode<K,V> q, ch;
+ searched = true;
+ if (((ch = p.left) != null &&
+ (q = ch.findTreeNode(h, k, kc)) != null) ||
+ ((ch = p.right) != null &&
+ (q = ch.findTreeNode(h, k, kc)) != null))
+ return q;
+ }
+ dir = tieBreakOrder(k, pk);
}
+
TreeNode<K,V> xp = p;
- if ((p = (dir < 0) ? p.left : p.right) == null) {
+ if ((p = (dir <= 0) ? p.left : p.right) == null) {
TreeNode<K,V> x, f = first;
first = x = new TreeNode<K,V>(h, k, v, f, xp);
if (f != null)
f.prev = x;
- if (dir < 0)
+ if (dir <= 0)
xp.left = x;
else
xp.right = x;
@@ -2308,7 +2389,7 @@ public class ConcurrentHashMap<K,V> extends java.util.AbstractMap<K,V>
static <K,V> TreeNode<K,V> balanceDeletion(TreeNode<K,V> root,
TreeNode<K,V> x) {
- for (TreeNode<K,V> xp, xpl, xpr;;) {
+ for (TreeNode<K,V> xp, xpl, xpr;;) {
if (x == null || x == root)
return root;
else if ((xp = x.parent) == null) {
@@ -2440,8 +2521,20 @@ public class ConcurrentHashMap<K,V> extends java.util.AbstractMap<K,V>
/* ----------------Table Traversal -------------- */
/**
+ * Records the table, its length, and current traversal index for a
+ * traverser that must process a region of a forwarded table before
+ * proceeding with current table.
+ */
+ static final class TableStack<K,V> {
+ int length;
+ int index;
+ Node<K,V>[] tab;
+ TableStack<K,V> next;
+ }
+
+ /**
* Encapsulates traversal for methods such as containsValue; also
- * serves as a base class for other iterators.
+ * serves as a base class for other iterators and spliterators.
*
* Method advance visits once each still-valid node that was
* reachable upon iterator construction. It might miss some that
@@ -2463,6 +2556,7 @@ public class ConcurrentHashMap<K,V> extends java.util.AbstractMap<K,V>
static class Traverser<K,V> {
Node<K,V>[] tab; // current table; updated if resized
Node<K,V> next; // the next entry to use
+ TableStack<K,V> stack, spare; // to save/restore on ForwardingNodes
int index; // index of bin to use next
int baseIndex; // current index of initial table
int baseLimit; // index bound for initial table
@@ -2484,16 +2578,17 @@ public class ConcurrentHashMap<K,V> extends java.util.AbstractMap<K,V>
if ((e = next) != null)
e = e.next;
for (;;) {
- Node<K,V>[] t; int i, n; K ek; // must use locals in checks
+ Node<K,V>[] t; int i, n; // must use locals in checks
if (e != null)
return next = e;
if (baseIndex >= baseLimit || (t = tab) == null ||
(n = t.length) <= (i = index) || i < 0)
return next = null;
- if ((e = tabAt(t, index)) != null && e.hash < 0) {
+ if ((e = tabAt(t, i)) != null && e.hash < 0) {
if (e instanceof ForwardingNode) {
tab = ((ForwardingNode<K,V>)e).nextTable;
e = null;
+ pushState(t, i, n);
continue;
}
else if (e instanceof TreeBin)
@@ -2501,9 +2596,48 @@ public class ConcurrentHashMap<K,V> extends java.util.AbstractMap<K,V>
else
e = null;
}
- if ((index += baseSize) >= n)
- index = ++baseIndex; // visit upper slots if present
+ if (stack != null)
+ recoverState(n);
+ else if ((index = i + baseSize) >= n)
+ index = ++baseIndex; // visit upper slots if present
+ }
+ }
+
+ /**
+ * Saves traversal state upon encountering a forwarding node.
+ */
+ private void pushState(Node<K,V>[] t, int i, int n) {
+ TableStack<K,V> s = spare; // reuse if possible
+ if (s != null)
+ spare = s.next;
+ else
+ s = new TableStack<K,V>();
+ s.tab = t;
+ s.length = n;
+ s.index = i;
+ s.next = stack;
+ stack = s;
+ }
+
+ /**
+ * Possibly pops traversal state.
+ *
+ * @param n length of current table
+ */
+ private void recoverState(int n) {
+ TableStack<K,V> s; int len;
+ while ((s = stack) != null && (index += (len = s.length)) >= n) {
+ n = len;
+ index = s.index;
+ tab = s.tab;
+ s.tab = null;
+ TableStack<K,V> next = s.next;
+ s.next = spare; // save for reuse
+ stack = next;
+ spare = s;
}
+ if (s == null && (index += baseSize) >= n)
+ index = ++baseIndex;
}
}
@@ -2639,7 +2773,6 @@ public class ConcurrentHashMap<K,V> extends java.util.AbstractMap<K,V>
/**
* Base class for views.
- *
*/
abstract static class CollectionView<K,V,E>
implements Collection<E>, java.io.Serializable {
@@ -2797,13 +2930,12 @@ public class ConcurrentHashMap<K,V> extends java.util.AbstractMap<K,V>
* common value. This class cannot be directly instantiated.
* See {@link #keySet() keySet()},
* {@link #keySet(Object) keySet(V)},
- * {@link #newKeySet() newKeySet()},
- * {@link #newKeySet(int) newKeySet(int)}.
*
* @since 1.8
*
* @hide
*/
+ // android-note: removed references to hidden APIs.
public static class KeySetView<K,V> extends CollectionView<K,V,K>
implements Set<K>, java.io.Serializable {
private static final long serialVersionUID = 7249069246763182397L;
@@ -3162,7 +3294,6 @@ public class ConcurrentHashMap<K,V> extends java.util.AbstractMap<K,V>
private static final sun.misc.Unsafe U;
private static final long SIZECTL;
private static final long TRANSFERINDEX;
- private static final long TRANSFERORIGIN;
private static final long BASECOUNT;
private static final long CELLSBUSY;
private static final long CELLVALUE;
@@ -3177,8 +3308,6 @@ public class ConcurrentHashMap<K,V> extends java.util.AbstractMap<K,V>
(k.getDeclaredField("sizeCtl"));
TRANSFERINDEX = U.objectFieldOffset
(k.getDeclaredField("transferIndex"));
- TRANSFERORIGIN = U.objectFieldOffset
- (k.getDeclaredField("transferOrigin"));
BASECOUNT = U.objectFieldOffset
(k.getDeclaredField("baseCount"));
CELLSBUSY = U.objectFieldOffset
@@ -3195,6 +3324,10 @@ public class ConcurrentHashMap<K,V> extends java.util.AbstractMap<K,V>
} catch (Exception e) {
throw new Error(e);
}
+
+ // Reduce the risk of rare disastrous classloading in first call to
+ // LockSupport.park: https://bugs.openjdk.java.net/browse/JDK-8074773
+ Class<?> ensureLoaded = LockSupport.class;
}
}
diff --git a/luni/src/main/java/java/util/concurrent/ConcurrentLinkedQueue.java b/luni/src/main/java/java/util/concurrent/ConcurrentLinkedQueue.java
index b39a533..9010cbe 100644
--- a/luni/src/main/java/java/util/concurrent/ConcurrentLinkedQueue.java
+++ b/luni/src/main/java/java/util/concurrent/ConcurrentLinkedQueue.java
@@ -32,9 +32,9 @@ import java.util.Queue;
* does not permit the use of {@code null} elements.
*
* <p>This implementation employs an efficient <em>non-blocking</em>
- * algorithm based on one described in <a
- * href="http://www.cs.rochester.edu/u/michael/PODC96.html"> Simple,
- * Fast, and Practical Non-Blocking and Blocking Concurrent Queue
+ * algorithm based on one described in
+ * <a href="http://www.cs.rochester.edu/~scott/papers/1996_PODC_queues.pdf">
+ * Simple, Fast, and Practical Non-Blocking and Blocking Concurrent Queue
* Algorithms</a> by Maged M. Michael and Michael L. Scott.
*
* <p>Iterators are <i>weakly consistent</i>, returning elements
diff --git a/luni/src/main/java/java/util/concurrent/ConcurrentMap.java b/luni/src/main/java/java/util/concurrent/ConcurrentMap.java
index 27feeb2..1391f04 100644
--- a/luni/src/main/java/java/util/concurrent/ConcurrentMap.java
+++ b/luni/src/main/java/java/util/concurrent/ConcurrentMap.java
@@ -5,6 +5,7 @@
*/
package java.util.concurrent;
+
import java.util.Map;
// BEGIN android-note
diff --git a/luni/src/main/java/java/util/concurrent/ConcurrentNavigableMap.java b/luni/src/main/java/java/util/concurrent/ConcurrentNavigableMap.java
index e87fbee..17890ff 100644
--- a/luni/src/main/java/java/util/concurrent/ConcurrentNavigableMap.java
+++ b/luni/src/main/java/java/util/concurrent/ConcurrentNavigableMap.java
@@ -5,6 +5,7 @@
*/
package java.util.concurrent;
+
import java.util.*;
// BEGIN android-note
diff --git a/luni/src/main/java/java/util/concurrent/ConcurrentSkipListMap.java b/luni/src/main/java/java/util/concurrent/ConcurrentSkipListMap.java
index 803cd49..0e8b64a 100644
--- a/luni/src/main/java/java/util/concurrent/ConcurrentSkipListMap.java
+++ b/luni/src/main/java/java/util/concurrent/ConcurrentSkipListMap.java
@@ -5,6 +5,7 @@
*/
package java.util.concurrent;
+
import java.util.*;
// BEGIN android-note
@@ -215,7 +216,7 @@ public class ConcurrentSkipListMap<K,V> extends AbstractMap<K,V>
* highly contended cases.
*
* Unlike most skip-list implementations, index insertion and
- * deletion here require a separate traversal pass occuring after
+ * deletion here require a separate traversal pass occurring after
* the base-level action, to add or remove index nodes. This adds
* to single-threaded overhead, but improves contended
* multithreaded performance by narrowing interference windows,
@@ -293,11 +294,13 @@ public class ConcurrentSkipListMap<K,V> extends AbstractMap<K,V>
private static final long serialVersionUID = -8627078645895051609L;
- /**
- * Generates the initial random seed for the cheaper per-instance
- * random number generators used in randomLevel.
- */
- private static final Random seedGenerator = new Random();
+// BEGIN android-removed
+// /**
+// * Generates the initial random seed for the cheaper per-instance
+// * random number generators used in randomLevel.
+// */
+// private static final Random seedGenerator = new Random();
+// END android-removed
/**
* Special value used to identify base-level header
@@ -341,7 +344,13 @@ public class ConcurrentSkipListMap<K,V> extends AbstractMap<K,V>
entrySet = null;
values = null;
descendingMap = null;
- randomSeed = seedGenerator.nextInt() | 0x0100; // ensure nonzero
+ // BEGIN android-changed
+ //
+ // Most processes are forked from the zygote, so they'll end up
+ // with the same random seed unless we take additional post fork
+ // measures.
+ randomSeed = Math.randomIntInternal() | 0x0100; // ensure nonzero
+ // END android-changed
head = new HeadIndex<K,V>(new Node<K,V>(null, BASE_HEADER, null),
null, null, 1);
}
@@ -2350,8 +2359,8 @@ public class ConcurrentSkipListMap<K,V> extends AbstractMap<K,V>
}
static final class Values<E> extends AbstractCollection<E> {
- private final ConcurrentNavigableMap<?, E> m;
- Values(ConcurrentNavigableMap<?, E> map) {
+ private final ConcurrentNavigableMap<?,E> m;
+ Values(ConcurrentNavigableMap<?,E> map) {
m = map;
}
public Iterator<E> iterator() {
@@ -2558,7 +2567,7 @@ public class ConcurrentSkipListMap<K,V> extends AbstractMap<K,V>
}
/**
- * Returns lowest absolute key (ignoring directonality).
+ * Returns lowest absolute key (ignoring directionality).
*/
private K lowestKey() {
ConcurrentSkipListMap.Node<K,V> n = loNode();
@@ -2569,7 +2578,7 @@ public class ConcurrentSkipListMap<K,V> extends AbstractMap<K,V>
}
/**
- * Returns highest absolute key (ignoring directonality).
+ * Returns highest absolute key (ignoring directionality).
*/
private K highestKey() {
ConcurrentSkipListMap.Node<K,V> n = hiNode();
diff --git a/luni/src/main/java/java/util/concurrent/ConcurrentSkipListSet.java b/luni/src/main/java/java/util/concurrent/ConcurrentSkipListSet.java
index f1402b6..13f1a43 100644
--- a/luni/src/main/java/java/util/concurrent/ConcurrentSkipListSet.java
+++ b/luni/src/main/java/java/util/concurrent/ConcurrentSkipListSet.java
@@ -5,6 +5,7 @@
*/
package java.util.concurrent;
+
import java.util.*;
// BEGIN android-note
diff --git a/luni/src/main/java/java/util/concurrent/CopyOnWriteArraySet.java b/luni/src/main/java/java/util/concurrent/CopyOnWriteArraySet.java
index 6fa8feb..347ed14 100644
--- a/luni/src/main/java/java/util/concurrent/CopyOnWriteArraySet.java
+++ b/luni/src/main/java/java/util/concurrent/CopyOnWriteArraySet.java
@@ -5,6 +5,7 @@
*/
package java.util.concurrent;
+
import java.util.*;
// BEGIN android-note
diff --git a/luni/src/main/java/java/util/concurrent/CountDownLatch.java b/luni/src/main/java/java/util/concurrent/CountDownLatch.java
index fe0fa65..77093f7 100644
--- a/luni/src/main/java/java/util/concurrent/CountDownLatch.java
+++ b/luni/src/main/java/java/util/concurrent/CountDownLatch.java
@@ -5,6 +5,7 @@
*/
package java.util.concurrent;
+
import java.util.concurrent.locks.AbstractQueuedSynchronizer;
/**
diff --git a/luni/src/main/java/java/util/concurrent/CountedCompleter.java b/luni/src/main/java/java/util/concurrent/CountedCompleter.java
index d5f794e..b868037 100644
--- a/luni/src/main/java/java/util/concurrent/CountedCompleter.java
+++ b/luni/src/main/java/java/util/concurrent/CountedCompleter.java
@@ -686,7 +686,7 @@ public abstract class CountedCompleter<T> extends ForkJoinTask<T> {
}
/**
- * Returns the result of the computation. By default
+ * Returns the result of the computation. By default,
* returns {@code null}, which is appropriate for {@code Void}
* actions, but in other cases should be overridden, almost
* always to return a field or function of a field that
diff --git a/luni/src/main/java/java/util/concurrent/CyclicBarrier.java b/luni/src/main/java/java/util/concurrent/CyclicBarrier.java
index e1a7bee..d698501 100644
--- a/luni/src/main/java/java/util/concurrent/CyclicBarrier.java
+++ b/luni/src/main/java/java/util/concurrent/CyclicBarrier.java
@@ -5,6 +5,7 @@
*/
package java.util.concurrent;
+
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;
@@ -125,7 +126,7 @@ public class CyclicBarrier {
private final Condition trip = lock.newCondition();
/** The number of parties */
private final int parties;
- /* The command to run when tripped */
+ /** The command to run when tripped */
private final Runnable barrierCommand;
/** The current generation */
private Generation generation = new Generation();
diff --git a/luni/src/main/java/java/util/concurrent/DelayQueue.java b/luni/src/main/java/java/util/concurrent/DelayQueue.java
index 945249e..e4a715e 100644
--- a/luni/src/main/java/java/util/concurrent/DelayQueue.java
+++ b/luni/src/main/java/java/util/concurrent/DelayQueue.java
@@ -5,6 +5,7 @@
*/
package java.util.concurrent;
+
import static java.util.concurrent.TimeUnit.NANOSECONDS;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;
@@ -60,7 +61,7 @@ public class DelayQueue<E extends Delayed> extends AbstractQueue<E>
* signalled. So waiting threads must be prepared to acquire
* and lose leadership while waiting.
*/
- private Thread leader = null;
+ private Thread leader;
/**
* Condition signalled when a newer element becomes available
diff --git a/luni/src/main/java/java/util/concurrent/Exchanger.java b/luni/src/main/java/java/util/concurrent/Exchanger.java
index 01d5960..60871b4 100644
--- a/luni/src/main/java/java/util/concurrent/Exchanger.java
+++ b/luni/src/main/java/java/util/concurrent/Exchanger.java
@@ -6,9 +6,6 @@
*/
package java.util.concurrent;
-import java.util.concurrent.atomic.AtomicInteger;
-import java.util.concurrent.atomic.AtomicReference;
-import java.util.concurrent.locks.LockSupport;
/**
* A synchronization point at which threads can pair and swap elements
diff --git a/luni/src/main/java/java/util/concurrent/Executor.java b/luni/src/main/java/java/util/concurrent/Executor.java
index f55209a..095ebfc 100644
--- a/luni/src/main/java/java/util/concurrent/Executor.java
+++ b/luni/src/main/java/java/util/concurrent/Executor.java
@@ -12,7 +12,7 @@ package java.util.concurrent;
* mechanics of how each task will be run, including details of thread
* use, scheduling, etc. An {@code Executor} is normally used
* instead of explicitly creating threads. For example, rather than
- * invoking {@code new Thread(new(RunnableTask())).start()} for each
+ * invoking {@code new Thread(new RunnableTask()).start()} for each
* of a set of tasks, you might use:
*
* <pre>
@@ -52,7 +52,7 @@ package java.util.concurrent;
*
* <pre> {@code
* class SerialExecutor implements Executor {
- * final Queue<Runnable> tasks = new ArrayDeque<Runnable>();
+ * final Queue<Runnable> tasks = new ArrayDeque<>();
* final Executor executor;
* Runnable active;
*
@@ -61,7 +61,7 @@ package java.util.concurrent;
* }
*
* public synchronized void execute(final Runnable r) {
- * tasks.offer(new Runnable() {
+ * tasks.add(new Runnable() {
* public void run() {
* try {
* r.run();
diff --git a/luni/src/main/java/java/util/concurrent/ExecutorCompletionService.java b/luni/src/main/java/java/util/concurrent/ExecutorCompletionService.java
index c0d6006..9514246 100644
--- a/luni/src/main/java/java/util/concurrent/ExecutorCompletionService.java
+++ b/luni/src/main/java/java/util/concurrent/ExecutorCompletionService.java
@@ -132,7 +132,7 @@ public class ExecutorCompletionService<V> implements CompletionService<V> {
* @param completionQueue the queue to use as the completion queue
* normally one dedicated for use by this service. This
* queue is treated as unbounded -- failed attempted
- * {@code Queue.add} operations for completed taskes cause
+ * {@code Queue.add} operations for completed tasks cause
* them not to be retrievable.
* @throws NullPointerException if executor or completionQueue are {@code null}
*/
diff --git a/luni/src/main/java/java/util/concurrent/ExecutorService.java b/luni/src/main/java/java/util/concurrent/ExecutorService.java
index 4599f59..2173529 100644
--- a/luni/src/main/java/java/util/concurrent/ExecutorService.java
+++ b/luni/src/main/java/java/util/concurrent/ExecutorService.java
@@ -5,6 +5,7 @@
*/
package java.util.concurrent;
+
import java.util.List;
import java.util.Collection;
@@ -29,8 +30,8 @@ import java.util.Collection;
* reclamation of its resources.
*
* <p>Method {@code submit} extends base method {@link
- * Executor#execute} by creating and returning a {@link Future} that
- * can be used to cancel execution and/or wait for completion.
+ * Executor#execute(Runnable)} by creating and returning a {@link Future}
+ * that can be used to cancel execution and/or wait for completion.
* Methods {@code invokeAny} and {@code invokeAll} perform the most
* commonly useful forms of bulk execution, executing a collection of
* tasks and then waiting for at least one, or all, to
diff --git a/luni/src/main/java/java/util/concurrent/Executors.java b/luni/src/main/java/java/util/concurrent/Executors.java
index 53c68fc..8731372 100644
--- a/luni/src/main/java/java/util/concurrent/Executors.java
+++ b/luni/src/main/java/java/util/concurrent/Executors.java
@@ -5,6 +5,7 @@
*/
package java.util.concurrent;
+
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.security.AccessControlContext;
diff --git a/luni/src/main/java/java/util/concurrent/ForkJoinPool.java b/luni/src/main/java/java/util/concurrent/ForkJoinPool.java
index 9448616..5bcac28 100644
--- a/luni/src/main/java/java/util/concurrent/ForkJoinPool.java
+++ b/luni/src/main/java/java/util/concurrent/ForkJoinPool.java
@@ -12,14 +12,6 @@ import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
-import java.util.concurrent.AbstractExecutorService;
-import java.util.concurrent.Callable;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Future;
-import java.util.concurrent.RejectedExecutionException;
-import java.util.concurrent.RunnableFuture;
-import java.util.concurrent.ThreadLocalRandom;
-import java.util.concurrent.TimeUnit;
/**
* An {@link ExecutorService} for running {@link ForkJoinTask}s.
@@ -498,6 +490,7 @@ public class ForkJoinPool extends AbstractExecutorService {
* (7) Exported methods
* (8) Static block initializing statics in minimally dependent order
*/
+ // android-note: Removed references to CountedCompleters.
// Static utilities
@@ -524,8 +517,8 @@ public class ForkJoinPool extends AbstractExecutorService {
* Returns a new worker thread operating in the given pool.
*
* @param pool the pool this thread works in
- * @throws NullPointerException if the pool is null
* @return the new worker thread
+ * @throws NullPointerException if the pool is null
*/
public ForkJoinWorkerThread newThread(ForkJoinPool pool);
}
@@ -2090,7 +2083,7 @@ public class ForkJoinPool extends AbstractExecutorService {
w.currentSteal = ps;
}
}
- else if (active) { // decrement active count without queuing
+ else if (active) { // decrement active count without queuing
long nc = ((c = ctl) & ~AC_MASK) | ((c & AC_MASK) - AC_UNIT);
if ((int)(nc >> AC_SHIFT) + parallelism == 0)
break; // bypass decrement-then-increment
diff --git a/luni/src/main/java/java/util/concurrent/ForkJoinTask.java b/luni/src/main/java/java/util/concurrent/ForkJoinTask.java
index c6bc6de..d34cae3 100644
--- a/luni/src/main/java/java/util/concurrent/ForkJoinTask.java
+++ b/luni/src/main/java/java/util/concurrent/ForkJoinTask.java
@@ -12,14 +12,6 @@ import java.util.List;
import java.util.RandomAccess;
import java.lang.ref.WeakReference;
import java.lang.ref.ReferenceQueue;
-import java.util.concurrent.Callable;
-import java.util.concurrent.CancellationException;
-import java.util.concurrent.ExecutionException;
-import java.util.concurrent.Future;
-import java.util.concurrent.RejectedExecutionException;
-import java.util.concurrent.RunnableFuture;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.TimeoutException;
import java.util.concurrent.locks.ReentrantLock;
import java.lang.reflect.Constructor;
@@ -177,6 +169,8 @@ import java.lang.reflect.Constructor;
* @since 1.7
* @author Doug Lea
*/
+// android-note: Removed references to hidden apis commonPool, CountedCompleter
+// etc.
public abstract class ForkJoinTask<V> implements Future<V>, Serializable {
/*
@@ -407,11 +401,13 @@ public abstract class ForkJoinTask<V> implements Future<V>, Serializable {
final Throwable ex;
ExceptionNode next;
final long thrower; // use id not ref to avoid weak cycles
+ final int hashCode; // store task hashCode before weak ref disappears
ExceptionNode(ForkJoinTask<?> task, Throwable ex, ExceptionNode next) {
super(task, exceptionTableRefQueue);
this.ex = ex;
this.next = next;
this.thrower = Thread.currentThread().getId();
+ this.hashCode = System.identityHashCode(task);
}
}
@@ -573,9 +569,9 @@ public abstract class ForkJoinTask<V> implements Future<V>, Serializable {
private static void expungeStaleExceptions() {
for (Object x; (x = exceptionTableRefQueue.poll()) != null;) {
if (x instanceof ExceptionNode) {
- ForkJoinTask<?> key = ((ExceptionNode)x).get();
+ int hashCode = ((ExceptionNode)x).hashCode;
ExceptionNode[] t = exceptionTable;
- int i = System.identityHashCode(key) & (t.length - 1);
+ int i = hashCode & (t.length - 1);
ExceptionNode e = t[i];
ExceptionNode pred = null;
while (e != null) {
@@ -1413,8 +1409,6 @@ public abstract class ForkJoinTask<V> implements Future<V>, Serializable {
try {
result = callable.call();
return true;
- } catch (Error err) {
- throw err;
} catch (RuntimeException rex) {
throw rex;
} catch (Exception ex) {
diff --git a/luni/src/main/java/java/util/concurrent/FutureTask.java b/luni/src/main/java/java/util/concurrent/FutureTask.java
index 114fe49..5e24fc8 100644
--- a/luni/src/main/java/java/util/concurrent/FutureTask.java
+++ b/luni/src/main/java/java/util/concurrent/FutureTask.java
@@ -5,6 +5,7 @@
*/
package java.util.concurrent;
+
import java.util.concurrent.locks.LockSupport;
/**
@@ -134,7 +135,7 @@ public class FutureTask<V> implements RunnableFuture<V> {
public boolean cancel(boolean mayInterruptIfRunning) {
if (!(state == NEW &&
- UNSAFE.compareAndSwapInt(this, stateOffset, NEW,
+ U.compareAndSwapInt(this, STATE, NEW,
mayInterruptIfRunning ? INTERRUPTING : CANCELLED)))
return false;
try { // in case call to interrupt throws exception
@@ -144,7 +145,7 @@ public class FutureTask<V> implements RunnableFuture<V> {
if (t != null)
t.interrupt();
} finally { // final state
- UNSAFE.putOrderedInt(this, stateOffset, INTERRUPTED);
+ U.putOrderedInt(this, STATE, INTERRUPTED);
}
}
} finally {
@@ -198,9 +199,9 @@ public class FutureTask<V> implements RunnableFuture<V> {
* @param v the value
*/
protected void set(V v) {
- if (UNSAFE.compareAndSwapInt(this, stateOffset, NEW, COMPLETING)) {
+ if (U.compareAndSwapInt(this, STATE, NEW, COMPLETING)) {
outcome = v;
- UNSAFE.putOrderedInt(this, stateOffset, NORMAL); // final state
+ U.putOrderedInt(this, STATE, NORMAL); // final state
finishCompletion();
}
}
@@ -216,17 +217,16 @@ public class FutureTask<V> implements RunnableFuture<V> {
* @param t the cause of failure
*/
protected void setException(Throwable t) {
- if (UNSAFE.compareAndSwapInt(this, stateOffset, NEW, COMPLETING)) {
+ if (U.compareAndSwapInt(this, STATE, NEW, COMPLETING)) {
outcome = t;
- UNSAFE.putOrderedInt(this, stateOffset, EXCEPTIONAL); // final state
+ U.putOrderedInt(this, STATE, EXCEPTIONAL); // final state
finishCompletion();
}
}
public void run() {
if (state != NEW ||
- !UNSAFE.compareAndSwapObject(this, runnerOffset,
- null, Thread.currentThread()))
+ !U.compareAndSwapObject(this, RUNNER, null, Thread.currentThread()))
return;
try {
Callable<V> c = callable;
@@ -263,12 +263,11 @@ public class FutureTask<V> implements RunnableFuture<V> {
* designed for use with tasks that intrinsically execute more
* than once.
*
- * @return true if successfully run and reset
+ * @return {@code true} if successfully run and reset
*/
protected boolean runAndReset() {
if (state != NEW ||
- !UNSAFE.compareAndSwapObject(this, runnerOffset,
- null, Thread.currentThread()))
+ !U.compareAndSwapObject(this, RUNNER, null, Thread.currentThread()))
return false;
boolean ran = false;
int s = state;
@@ -335,7 +334,7 @@ public class FutureTask<V> implements RunnableFuture<V> {
private void finishCompletion() {
// assert state > COMPLETING;
for (WaitNode q; (q = waiters) != null;) {
- if (UNSAFE.compareAndSwapObject(this, waitersOffset, q, null)) {
+ if (U.compareAndSwapObject(this, WAITERS, q, null)) {
for (;;) {
Thread t = q.thread;
if (t != null) {
@@ -362,39 +361,61 @@ public class FutureTask<V> implements RunnableFuture<V> {
*
* @param timed true if use timed waits
* @param nanos time to wait, if timed
- * @return state upon completion
+ * @return state upon completion or at timeout
*/
private int awaitDone(boolean timed, long nanos)
throws InterruptedException {
- final long deadline = timed ? System.nanoTime() + nanos : 0L;
+ // The code below is very delicate, to achieve these goals:
+ // - call nanoTime exactly once for each call to park
+ // - if nanos <= 0, return promptly without allocation or nanoTime
+ // - if nanos == Long.MIN_VALUE, don't underflow
+ // - if nanos == Long.MAX_VALUE, and nanoTime is non-monotonic
+ // and we suffer a spurious wakeup, we will do no worse than
+ // to park-spin for a while
+ long startTime = 0L; // Special value 0L means not yet parked
WaitNode q = null;
boolean queued = false;
for (;;) {
- if (Thread.interrupted()) {
- removeWaiter(q);
- throw new InterruptedException();
- }
-
int s = state;
if (s > COMPLETING) {
if (q != null)
q.thread = null;
return s;
}
- else if (s == COMPLETING) // cannot time out yet
+ else if (s == COMPLETING)
+ // We may have already promised (via isDone) that we are done
+ // so never return empty-handed or throw InterruptedException
Thread.yield();
- else if (q == null)
+ else if (Thread.interrupted()) {
+ removeWaiter(q);
+ throw new InterruptedException();
+ }
+ else if (q == null) {
+ if (timed && nanos <= 0L)
+ return s;
q = new WaitNode();
+ }
else if (!queued)
- queued = UNSAFE.compareAndSwapObject(this, waitersOffset,
- q.next = waiters, q);
+ queued = U.compareAndSwapObject(this, WAITERS,
+ q.next = waiters, q);
else if (timed) {
- nanos = deadline - System.nanoTime();
- if (nanos <= 0L) {
- removeWaiter(q);
- return state;
+ final long parkNanos;
+ if (startTime == 0L) { // first time
+ startTime = System.nanoTime();
+ if (startTime == 0L)
+ startTime = 1L;
+ parkNanos = nanos;
+ } else {
+ long elapsed = System.nanoTime() - startTime;
+ if (elapsed >= nanos) {
+ removeWaiter(q);
+ return state;
+ }
+ parkNanos = nanos - elapsed;
}
- LockSupport.parkNanos(this, nanos);
+ // nanoTime may be slow; recheck before parking
+ if (state < COMPLETING)
+ LockSupport.parkNanos(this, parkNanos);
}
else
LockSupport.park(this);
@@ -425,8 +446,7 @@ public class FutureTask<V> implements RunnableFuture<V> {
if (pred.thread == null) // check for race
continue retry;
}
- else if (!UNSAFE.compareAndSwapObject(this, waitersOffset,
- q, s))
+ else if (!U.compareAndSwapObject(this, WAITERS, q, s))
continue retry;
}
break;
@@ -435,23 +455,25 @@ public class FutureTask<V> implements RunnableFuture<V> {
}
// Unsafe mechanics
- private static final sun.misc.Unsafe UNSAFE;
- private static final long stateOffset;
- private static final long runnerOffset;
- private static final long waitersOffset;
+ private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
+ private static final long STATE;
+ private static final long RUNNER;
+ private static final long WAITERS;
static {
try {
- UNSAFE = sun.misc.Unsafe.getUnsafe();
- Class<?> k = FutureTask.class;
- stateOffset = UNSAFE.objectFieldOffset
- (k.getDeclaredField("state"));
- runnerOffset = UNSAFE.objectFieldOffset
- (k.getDeclaredField("runner"));
- waitersOffset = UNSAFE.objectFieldOffset
- (k.getDeclaredField("waiters"));
+ STATE = U.objectFieldOffset
+ (FutureTask.class.getDeclaredField("state"));
+ RUNNER = U.objectFieldOffset
+ (FutureTask.class.getDeclaredField("runner"));
+ WAITERS = U.objectFieldOffset
+ (FutureTask.class.getDeclaredField("waiters"));
} catch (Exception e) {
throw new Error(e);
}
+
+ // Reduce the risk of rare disastrous classloading in first call to
+ // LockSupport.park: https://bugs.openjdk.java.net/browse/JDK-8074773
+ Class<?> ensureLoaded = LockSupport.class;
}
}
diff --git a/luni/src/main/java/java/util/concurrent/LinkedTransferQueue.java b/luni/src/main/java/java/util/concurrent/LinkedTransferQueue.java
index a041fb1..db48420 100644
--- a/luni/src/main/java/java/util/concurrent/LinkedTransferQueue.java
+++ b/luni/src/main/java/java/util/concurrent/LinkedTransferQueue.java
@@ -11,7 +11,6 @@ import java.util.Collection;
import java.util.Iterator;
import java.util.NoSuchElementException;
import java.util.Queue;
-import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.LockSupport;
// BEGIN android-note
@@ -76,7 +75,7 @@ public class LinkedTransferQueue<E> extends AbstractQueue<E>
*
* A FIFO dual queue may be implemented using a variation of the
* Michael & Scott (M&S) lock-free queue algorithm
- * (http://www.cs.rochester.edu/u/scott/papers/1996_PODC_queues.pdf).
+ * (http://www.cs.rochester.edu/~scott/papers/1996_PODC_queues.pdf).
* It maintains two pointer fields, "head", pointing to a
* (matched) node that in turn points to the first actual
* (unmatched) queue node (or null if empty); and "tail" that
@@ -1313,5 +1312,9 @@ public class LinkedTransferQueue<E> extends AbstractQueue<E>
} catch (Exception e) {
throw new Error(e);
}
+
+ // Reduce the risk of rare disastrous classloading in first call to
+ // LockSupport.park: https://bugs.openjdk.java.net/browse/JDK-8074773
+ Class<?> ensureLoaded = LockSupport.class;
}
}
diff --git a/luni/src/main/java/java/util/concurrent/Phaser.java b/luni/src/main/java/java/util/concurrent/Phaser.java
index a97d187..c5faf16 100644
--- a/luni/src/main/java/java/util/concurrent/Phaser.java
+++ b/luni/src/main/java/java/util/concurrent/Phaser.java
@@ -6,8 +6,6 @@
package java.util.concurrent;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.TimeoutException;
import java.util.concurrent.atomic.AtomicReference;
import java.util.concurrent.locks.LockSupport;
@@ -1128,5 +1126,9 @@ public class Phaser {
} catch (Exception e) {
throw new Error(e);
}
+
+ // Reduce the risk of rare disastrous classloading in first call to
+ // LockSupport.park: https://bugs.openjdk.java.net/browse/JDK-8074773
+ Class<?> ensureLoaded = LockSupport.class;
}
}
diff --git a/luni/src/main/java/java/util/concurrent/PriorityBlockingQueue.java b/luni/src/main/java/java/util/concurrent/PriorityBlockingQueue.java
index 0f9e715..40b3510 100644
--- a/luni/src/main/java/java/util/concurrent/PriorityBlockingQueue.java
+++ b/luni/src/main/java/java/util/concurrent/PriorityBlockingQueue.java
@@ -190,7 +190,7 @@ public class PriorityBlockingQueue<E> extends AbstractQueue<E>
/**
* Creates a {@code PriorityBlockingQueue} containing the elements
* in the specified collection. If the specified collection is a
- * {@link SortedSet} or a {@link PriorityQueue}, this
+ * {@link SortedSet} or a {@link PriorityQueue}, this
* priority queue will be ordered according to the same ordering.
* Otherwise, this priority queue will be ordered according to the
* {@linkplain Comparable natural ordering} of its elements.
diff --git a/luni/src/main/java/java/util/concurrent/RecursiveTask.java b/luni/src/main/java/java/util/concurrent/RecursiveTask.java
index 80baa52..d201bd6 100644
--- a/luni/src/main/java/java/util/concurrent/RecursiveTask.java
+++ b/luni/src/main/java/java/util/concurrent/RecursiveTask.java
@@ -46,6 +46,7 @@ public abstract class RecursiveTask<V> extends ForkJoinTask<V> {
/**
* The main computation performed by this task.
+ * @return the result of the computation
*/
protected abstract V compute();
diff --git a/luni/src/main/java/java/util/concurrent/ScheduledExecutorService.java b/luni/src/main/java/java/util/concurrent/ScheduledExecutorService.java
index b978fae..d5bae22 100644
--- a/luni/src/main/java/java/util/concurrent/ScheduledExecutorService.java
+++ b/luni/src/main/java/java/util/concurrent/ScheduledExecutorService.java
@@ -16,9 +16,9 @@ package java.util.concurrent;
* {@code scheduleWithFixedDelay} methods create and execute tasks
* that run periodically until cancelled.
*
- * <p>Commands submitted using the {@link Executor#execute} and
- * {@link ExecutorService} {@code submit} methods are scheduled with
- * a requested delay of zero. Zero and negative delays (but not
+ * <p>Commands submitted using the {@link Executor#execute(Runnable)}
+ * and {@link ExecutorService} {@code submit} methods are scheduled
+ * with a requested delay of zero. Zero and negative delays (but not
* periods) are also allowed in {@code schedule} methods, and are
* treated as requests for immediate execution.
*
@@ -33,7 +33,7 @@ package java.util.concurrent;
* which the task is enabled due to network time synchronization
* protocols, clock drift, or other factors.
*
- * The {@link Executors} class provides convenient factory methods for
+ * <p>The {@link Executors} class provides convenient factory methods for
* the ScheduledExecutorService implementations provided in this package.
*
* <h3>Usage Example</h3>
diff --git a/luni/src/main/java/java/util/concurrent/ScheduledThreadPoolExecutor.java b/luni/src/main/java/java/util/concurrent/ScheduledThreadPoolExecutor.java
index 483981d..d01cc33 100644
--- a/luni/src/main/java/java/util/concurrent/ScheduledThreadPoolExecutor.java
+++ b/luni/src/main/java/java/util/concurrent/ScheduledThreadPoolExecutor.java
@@ -5,7 +5,9 @@
*/
package java.util.concurrent;
+
import static java.util.concurrent.TimeUnit.NANOSECONDS;
+import static java.util.concurrent.TimeUnit.MILLISECONDS;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;
@@ -17,11 +19,11 @@ import java.util.*;
/**
* A {@link ThreadPoolExecutor} that can additionally schedule
- * commands to run after a given delay, or to execute
- * periodically. This class is preferable to {@link java.util.Timer}
- * when multiple worker threads are needed, or when the additional
- * flexibility or capabilities of {@link ThreadPoolExecutor} (which
- * this class extends) are required.
+ * commands to run after a given delay, or to execute periodically.
+ * This class is preferable to {@link java.util.Timer} when multiple
+ * worker threads are needed, or when the additional flexibility or
+ * capabilities of {@link ThreadPoolExecutor} (which this class
+ * extends) are required.
*
* <p>Delayed tasks execute no sooner than they are enabled, but
* without any real-time guarantees about when, after they are
@@ -35,9 +37,9 @@ import java.util.*;
* elapses. While this enables further inspection and monitoring, it
* may also cause unbounded retention of cancelled tasks.
*
- * <p>Successive executions of a task scheduled via
- * {@code scheduleAtFixedRate} or
- * {@code scheduleWithFixedDelay} do not overlap. While different
+ * <p>Successive executions of a periodic task scheduled via
+ * {@link #scheduleAtFixedRate} or
+ * {@link #scheduleWithFixedDelay} do not overlap. While different
* executions may be performed by different threads, the effects of
* prior executions <a
* href="package-summary.html#MemoryVisibility"><i>happen-before</i></a>
@@ -132,7 +134,7 @@ public class ScheduledThreadPoolExecutor
private volatile boolean executeExistingDelayedTasksAfterShutdown = true;
/**
- * True if ScheduledFutureTask.cancel should remove from queue
+ * True if ScheduledFutureTask.cancel should remove from queue.
*/
private volatile boolean removeOnCancel = false;
@@ -159,10 +161,10 @@ public class ScheduledThreadPoolExecutor
private long time;
/**
- * Period in nanoseconds for repeating tasks. A positive
- * value indicates fixed-rate execution. A negative value
- * indicates fixed-delay execution. A value of 0 indicates a
- * non-repeating task.
+ * Period in nanoseconds for repeating tasks.
+ * A positive value indicates fixed-rate execution.
+ * A negative value indicates fixed-delay execution.
+ * A value of 0 indicates a non-repeating (one-shot) task.
*/
private final long period;
@@ -177,19 +179,21 @@ public class ScheduledThreadPoolExecutor
/**
* Creates a one-shot action with given nanoTime-based trigger time.
*/
- ScheduledFutureTask(Runnable r, V result, long ns) {
+ ScheduledFutureTask(Runnable r, V result, long triggerTime) {
super(r, result);
- this.time = ns;
+ this.time = triggerTime;
this.period = 0;
this.sequenceNumber = sequencer.getAndIncrement();
}
/**
- * Creates a periodic action with given nano time and period.
+ * Creates a periodic action with given nanoTime-based initial
+ * trigger time and period.
*/
- ScheduledFutureTask(Runnable r, V result, long ns, long period) {
+ ScheduledFutureTask(Runnable r, V result, long triggerTime,
+ long period) {
super(r, result);
- this.time = ns;
+ this.time = triggerTime;
this.period = period;
this.sequenceNumber = sequencer.getAndIncrement();
}
@@ -197,9 +201,9 @@ public class ScheduledThreadPoolExecutor
/**
* Creates a one-shot action with given nanoTime-based trigger time.
*/
- ScheduledFutureTask(Callable<V> callable, long ns) {
+ ScheduledFutureTask(Callable<V> callable, long triggerTime) {
super(callable);
- this.time = ns;
+ this.time = triggerTime;
this.period = 0;
this.sequenceNumber = sequencer.getAndIncrement();
}
@@ -389,6 +393,22 @@ public class ScheduledThreadPoolExecutor
}
/**
+ * The default keep-alive time for pool threads.
+ *
+ * Normally, this value is unused because all pool threads will be
+ * core threads, but if a user creates a pool with a corePoolSize
+ * of zero (against our advice), we keep a thread alive as long as
+ * there are queued tasks. If the keep alive time is zero (the
+ * historic value), we end up hot-spinning in getTask, wasting a
+ * CPU. But on the other hand, if we set the value too high, and
+ * users create a one-shot pool which they don't cleanly shutdown,
+ * the pool's non-daemon threads will prevent JVM termination. A
+ * small but non-zero value (relative to a JVM's lifetime) seems
+ * best.
+ */
+ private static final long DEFAULT_KEEPALIVE_MILLIS = 10L;
+
+ /**
* Creates a new {@code ScheduledThreadPoolExecutor} with the
* given core pool size.
*
@@ -397,7 +417,8 @@ public class ScheduledThreadPoolExecutor
* @throws IllegalArgumentException if {@code corePoolSize < 0}
*/
public ScheduledThreadPoolExecutor(int corePoolSize) {
- super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,
+ super(corePoolSize, Integer.MAX_VALUE,
+ DEFAULT_KEEPALIVE_MILLIS, MILLISECONDS,
new DelayedWorkQueue());
}
@@ -414,13 +435,14 @@ public class ScheduledThreadPoolExecutor
*/
public ScheduledThreadPoolExecutor(int corePoolSize,
ThreadFactory threadFactory) {
- super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,
+ super(corePoolSize, Integer.MAX_VALUE,
+ DEFAULT_KEEPALIVE_MILLIS, MILLISECONDS,
new DelayedWorkQueue(), threadFactory);
}
/**
- * Creates a new ScheduledThreadPoolExecutor with the given
- * initial parameters.
+ * Creates a new {@code ScheduledThreadPoolExecutor} with the
+ * given initial parameters.
*
* @param corePoolSize the number of threads to keep in the pool, even
* if they are idle, unless {@code allowCoreThreadTimeOut} is set
@@ -431,13 +453,14 @@ public class ScheduledThreadPoolExecutor
*/
public ScheduledThreadPoolExecutor(int corePoolSize,
RejectedExecutionHandler handler) {
- super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,
+ super(corePoolSize, Integer.MAX_VALUE,
+ DEFAULT_KEEPALIVE_MILLIS, MILLISECONDS,
new DelayedWorkQueue(), handler);
}
/**
- * Creates a new ScheduledThreadPoolExecutor with the given
- * initial parameters.
+ * Creates a new {@code ScheduledThreadPoolExecutor} with the
+ * given initial parameters.
*
* @param corePoolSize the number of threads to keep in the pool, even
* if they are idle, unless {@code allowCoreThreadTimeOut} is set
@@ -452,19 +475,20 @@ public class ScheduledThreadPoolExecutor
public ScheduledThreadPoolExecutor(int corePoolSize,
ThreadFactory threadFactory,
RejectedExecutionHandler handler) {
- super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,
+ super(corePoolSize, Integer.MAX_VALUE,
+ DEFAULT_KEEPALIVE_MILLIS, MILLISECONDS,
new DelayedWorkQueue(), threadFactory, handler);
}
/**
- * Returns the trigger time of a delayed action.
+ * Returns the nanoTime-based trigger time of a delayed action.
*/
private long triggerTime(long delay, TimeUnit unit) {
return triggerTime(unit.toNanos((delay < 0) ? 0 : delay));
}
/**
- * Returns the trigger time of a delayed action.
+ * Returns the nanoTime-based trigger time of a delayed action.
*/
long triggerTime(long delay) {
return now() +
@@ -497,7 +521,7 @@ public class ScheduledThreadPoolExecutor
TimeUnit unit) {
if (command == null || unit == null)
throw new NullPointerException();
- RunnableScheduledFuture<?> t = decorateTask(command,
+ RunnableScheduledFuture<Void> t = decorateTask(command,
new ScheduledFutureTask<Void>(command, null,
triggerTime(delay, unit)));
delayedExecute(t);
@@ -725,6 +749,7 @@ public class ScheduledThreadPoolExecutor
* {@code true}, future executions of existing periodic tasks will
* be cancelled.
*/
+ // android-note: Removed "throws SecurityException" doc.
public void shutdown() {
super.shutdown();
}
@@ -744,23 +769,28 @@ public class ScheduledThreadPoolExecutor
* fails to respond to interrupts may never terminate.
*
* @return list of tasks that never commenced execution.
- * Each element of this list is a {@link ScheduledFuture},
- * including those tasks submitted using {@code execute},
- * which are for scheduling purposes used as the basis of a
- * zero-delay {@code ScheduledFuture}.
+ * Each element of this list is a {@link ScheduledFuture}.
+ * For tasks submitted via one of the {@code schedule}
+ * methods, the element will be identical to the returned
+ * {@code ScheduledFuture}. For tasks submitted using
+ * {@link #execute}, the element will be a zero-delay {@code
+ * ScheduledFuture}.
*/
+ // android-note: Removed "throws SecurityException" doc.
public List<Runnable> shutdownNow() {
return super.shutdownNow();
}
/**
- * Returns the task queue used by this executor. Each element of
- * this queue is a {@link ScheduledFuture}, including those
- * tasks submitted using {@code execute} which are for scheduling
- * purposes used as the basis of a zero-delay
- * {@code ScheduledFuture}. Iteration over this queue is
- * <em>not</em> guaranteed to traverse tasks in the order in
- * which they will execute.
+ * Returns the task queue used by this executor.
+ * Each element of this list is a {@link ScheduledFuture}.
+ * For tasks submitted via one of the {@code schedule} methods, the
+ * element will be identical to the returned {@code ScheduledFuture}.
+ * For tasks submitted using {@link #execute}, the element will be a
+ * zero-delay {@code ScheduledFuture}.
+ *
+ * <p>Iteration over this queue is <em>not</em> guaranteed to traverse
+ * tasks in the order in which they will execute.
*
* @return the task queue
*/
@@ -803,7 +833,7 @@ public class ScheduledThreadPoolExecutor
private RunnableScheduledFuture<?>[] queue =
new RunnableScheduledFuture<?>[INITIAL_CAPACITY];
private final ReentrantLock lock = new ReentrantLock();
- private int size = 0;
+ private int size;
/**
* Thread designated to wait for the task at the head of the
@@ -821,7 +851,7 @@ public class ScheduledThreadPoolExecutor
* signalled. So waiting threads must be prepared to acquire
* and lose leadership while waiting.
*/
- private Thread leader = null;
+ private Thread leader;
/**
* Condition signalled when a newer task becomes available at the
@@ -1220,11 +1250,11 @@ public class ScheduledThreadPoolExecutor
* Snapshot iterator that works off copy of underlying q array.
*/
private class Itr implements Iterator<Runnable> {
- final RunnableScheduledFuture[] array;
+ final RunnableScheduledFuture<?>[] array;
int cursor = 0; // index of next element to return
int lastRet = -1; // index of last element, or -1 if no such
- Itr(RunnableScheduledFuture[] array) {
+ Itr(RunnableScheduledFuture<?>[] array) {
this.array = array;
}
diff --git a/luni/src/main/java/java/util/concurrent/Semaphore.java b/luni/src/main/java/java/util/concurrent/Semaphore.java
index 9ee18a8..b4b7edd 100644
--- a/luni/src/main/java/java/util/concurrent/Semaphore.java
+++ b/luni/src/main/java/java/util/concurrent/Semaphore.java
@@ -5,6 +5,7 @@
*/
package java.util.concurrent;
+
import java.util.Collection;
import java.util.concurrent.locks.AbstractQueuedSynchronizer;
diff --git a/luni/src/main/java/java/util/concurrent/SynchronousQueue.java b/luni/src/main/java/java/util/concurrent/SynchronousQueue.java
index ea6b3d1..69452af 100644
--- a/luni/src/main/java/java/util/concurrent/SynchronousQueue.java
+++ b/luni/src/main/java/java/util/concurrent/SynchronousQueue.java
@@ -6,6 +6,7 @@
*/
package java.util.concurrent;
+
import java.util.concurrent.locks.LockSupport;
import java.util.concurrent.locks.ReentrantLock;
import java.util.*;
@@ -1057,7 +1058,7 @@ public class SynchronousQueue<E> extends AbstractQueue<E>
}
/**
- * Sets the zeroeth element of the specified array to {@code null}
+ * Sets the zeroth element of the specified array to {@code null}
* (if the array has non-zero length) and returns it.
*
* @param a the array
@@ -1150,7 +1151,7 @@ public class SynchronousQueue<E> extends AbstractQueue<E>
/**
* Reconstitutes this queue from a stream (that is, deserializes it).
*/
- private void readObject(final java.io.ObjectInputStream s)
+ private void readObject(java.io.ObjectInputStream s)
throws java.io.IOException, ClassNotFoundException {
s.defaultReadObject();
if (waitingProducers instanceof FifoWaitQueue)
@@ -1172,4 +1173,9 @@ public class SynchronousQueue<E> extends AbstractQueue<E>
}
}
+ static {
+ // Reduce the risk of rare disastrous classloading in first call to
+ // LockSupport.park: https://bugs.openjdk.java.net/browse/JDK-8074773
+ Class<?> ensureLoaded = LockSupport.class;
+ }
}
diff --git a/luni/src/main/java/java/util/concurrent/ThreadLocalRandom.java b/luni/src/main/java/java/util/concurrent/ThreadLocalRandom.java
index 5baf75f..b007af2 100644
--- a/luni/src/main/java/java/util/concurrent/ThreadLocalRandom.java
+++ b/luni/src/main/java/java/util/concurrent/ThreadLocalRandom.java
@@ -107,9 +107,9 @@ public class ThreadLocalRandom extends Random {
*
* @param least the least value returned
* @param bound the upper bound (exclusive)
+ * @return the next value
* @throws IllegalArgumentException if least greater than or equal
* to bound
- * @return the next value
*/
public int nextInt(int least, int bound) {
if (least >= bound)
@@ -172,7 +172,7 @@ public class ThreadLocalRandom extends Random {
* @throws IllegalArgumentException if n is not positive
*/
public double nextDouble(double n) {
- if (n <= 0)
+ if (!(n > 0))
throw new IllegalArgumentException("n must be positive");
return nextDouble() * n;
}
diff --git a/luni/src/main/java/java/util/concurrent/ThreadPoolExecutor.java b/luni/src/main/java/java/util/concurrent/ThreadPoolExecutor.java
index 9586293..c484920 100644
--- a/luni/src/main/java/java/util/concurrent/ThreadPoolExecutor.java
+++ b/luni/src/main/java/java/util/concurrent/ThreadPoolExecutor.java
@@ -5,6 +5,7 @@
*/
package java.util.concurrent;
+
import java.util.concurrent.locks.AbstractQueuedSynchronizer;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;
@@ -582,7 +583,7 @@ public class ThreadPoolExecutor extends AbstractExecutorService {
this.thread = getThreadFactory().newThread(this);
}
- /** Delegates main run loop to outer runWorker */
+ /** Delegates main run loop to outer runWorker. */
public void run() {
runWorker(this);
}
@@ -1348,6 +1349,7 @@ public class ThreadPoolExecutor extends AbstractExecutorService {
* complete execution. Use {@link #awaitTermination awaitTermination}
* to do that.
*/
+ // android-note: Removed @throws SecurityException
public void shutdown() {
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
@@ -1377,6 +1379,7 @@ public class ThreadPoolExecutor extends AbstractExecutorService {
* cancels tasks via {@link Thread#interrupt}, so any task that
* fails to respond to interrupts may never terminate.
*/
+ // android-note: Removed @throws SecurityException
public List<Runnable> shutdownNow() {
List<Runnable> tasks;
final ReentrantLock mainLock = this.mainLock;
diff --git a/luni/src/main/java/java/util/concurrent/TimeUnit.java b/luni/src/main/java/java/util/concurrent/TimeUnit.java
index eb2c495..8e6a5f7 100644
--- a/luni/src/main/java/java/util/concurrent/TimeUnit.java
+++ b/luni/src/main/java/java/util/concurrent/TimeUnit.java
@@ -40,6 +40,9 @@ package java.util.concurrent;
* @author Doug Lea
*/
public enum TimeUnit {
+ /**
+ * Time unit representing one thousandth of a microsecond
+ */
NANOSECONDS {
public long toNanos(long d) { return d; }
public long toMicros(long d) { return d/(C1/C0); }
@@ -51,6 +54,10 @@ public enum TimeUnit {
public long convert(long d, TimeUnit u) { return u.toNanos(d); }
int excessNanos(long d, long m) { return (int)(d - (m*C2)); }
},
+
+ /**
+ * Time unit representing one thousandth of a millisecond
+ */
MICROSECONDS {
public long toNanos(long d) { return x(d, C1/C0, MAX/(C1/C0)); }
public long toMicros(long d) { return d; }
@@ -62,6 +69,10 @@ public enum TimeUnit {
public long convert(long d, TimeUnit u) { return u.toMicros(d); }
int excessNanos(long d, long m) { return (int)((d*C1) - (m*C2)); }
},
+
+ /**
+ * Time unit representing one thousandth of a second
+ */
MILLISECONDS {
public long toNanos(long d) { return x(d, C2/C0, MAX/(C2/C0)); }
public long toMicros(long d) { return x(d, C2/C1, MAX/(C2/C1)); }
@@ -73,6 +84,10 @@ public enum TimeUnit {
public long convert(long d, TimeUnit u) { return u.toMillis(d); }
int excessNanos(long d, long m) { return 0; }
},
+
+ /**
+ * Time unit representing one second
+ */
SECONDS {
public long toNanos(long d) { return x(d, C3/C0, MAX/(C3/C0)); }
public long toMicros(long d) { return x(d, C3/C1, MAX/(C3/C1)); }
@@ -84,6 +99,11 @@ public enum TimeUnit {
public long convert(long d, TimeUnit u) { return u.toSeconds(d); }
int excessNanos(long d, long m) { return 0; }
},
+
+ /**
+ * Time unit representing sixty seconds
+ * @since 1.6
+ */
MINUTES {
public long toNanos(long d) { return x(d, C4/C0, MAX/(C4/C0)); }
public long toMicros(long d) { return x(d, C4/C1, MAX/(C4/C1)); }
@@ -95,6 +115,11 @@ public enum TimeUnit {
public long convert(long d, TimeUnit u) { return u.toMinutes(d); }
int excessNanos(long d, long m) { return 0; }
},
+
+ /**
+ * Time unit representing sixty minutes
+ * @since 1.6
+ */
HOURS {
public long toNanos(long d) { return x(d, C5/C0, MAX/(C5/C0)); }
public long toMicros(long d) { return x(d, C5/C1, MAX/(C5/C1)); }
@@ -106,6 +131,11 @@ public enum TimeUnit {
public long convert(long d, TimeUnit u) { return u.toHours(d); }
int excessNanos(long d, long m) { return 0; }
},
+
+ /**
+ * Time unit representing twenty four hours
+ * @since 1.6
+ */
DAYS {
public long toNanos(long d) { return x(d, C6/C0, MAX/(C6/C0)); }
public long toMicros(long d) { return x(d, C6/C1, MAX/(C6/C1)); }
@@ -145,14 +175,13 @@ public enum TimeUnit {
// etc. are not declared abstract but otherwise act as abstract methods.
/**
- * Convert the given time duration in the given unit to this
- * unit. Conversions from finer to coarser granularities
- * truncate, so lose precision. For example converting
- * {@code 999} milliseconds to seconds results in
- * {@code 0}. Conversions from coarser to finer granularities
- * with arguments that would numerically overflow saturate to
- * {@code Long.MIN_VALUE} if negative or {@code Long.MAX_VALUE}
- * if positive.
+ * Converts the given time duration in the given unit to this unit.
+ * Conversions from finer to coarser granularities truncate, so
+ * lose precision. For example, converting {@code 999} milliseconds
+ * to seconds results in {@code 0}. Conversions from coarser to
+ * finer granularities with arguments that would numerically
+ * overflow saturate to {@code Long.MIN_VALUE} if negative or
+ * {@code Long.MAX_VALUE} if positive.
*
* <p>For example, to convert 10 minutes to milliseconds, use:
* {@code TimeUnit.MILLISECONDS.convert(10L, TimeUnit.MINUTES)}
@@ -168,60 +197,60 @@ public enum TimeUnit {
}
/**
- * Equivalent to {@code NANOSECONDS.convert(duration, this)}.
+ * Equivalent to
+ * {@link #convert(long, TimeUnit) NANOSECONDS.convert(duration, this)}.
* @param duration the duration
* @return the converted duration,
* or {@code Long.MIN_VALUE} if conversion would negatively
* overflow, or {@code Long.MAX_VALUE} if it would positively overflow.
- * @see #convert
*/
public long toNanos(long duration) {
throw new AbstractMethodError();
}
/**
- * Equivalent to {@code MICROSECONDS.convert(duration, this)}.
+ * Equivalent to
+ * {@link #convert(long, TimeUnit) MICROSECONDS.convert(duration, this)}.
* @param duration the duration
* @return the converted duration,
* or {@code Long.MIN_VALUE} if conversion would negatively
* overflow, or {@code Long.MAX_VALUE} if it would positively overflow.
- * @see #convert
*/
public long toMicros(long duration) {
throw new AbstractMethodError();
}
/**
- * Equivalent to {@code MILLISECONDS.convert(duration, this)}.
+ * Equivalent to
+ * {@link #convert(long, TimeUnit) MILLISECONDS.convert(duration, this)}.
* @param duration the duration
* @return the converted duration,
* or {@code Long.MIN_VALUE} if conversion would negatively
* overflow, or {@code Long.MAX_VALUE} if it would positively overflow.
- * @see #convert
*/
public long toMillis(long duration) {
throw new AbstractMethodError();
}
/**
- * Equivalent to {@code SECONDS.convert(duration, this)}.
+ * Equivalent to
+ * {@link #convert(long, TimeUnit) SECONDS.convert(duration, this)}.
* @param duration the duration
* @return the converted duration,
* or {@code Long.MIN_VALUE} if conversion would negatively
* overflow, or {@code Long.MAX_VALUE} if it would positively overflow.
- * @see #convert
*/
public long toSeconds(long duration) {
throw new AbstractMethodError();
}
/**
- * Equivalent to {@code MINUTES.convert(duration, this)}.
+ * Equivalent to
+ * {@link #convert(long, TimeUnit) MINUTES.convert(duration, this)}.
* @param duration the duration
* @return the converted duration,
* or {@code Long.MIN_VALUE} if conversion would negatively
* overflow, or {@code Long.MAX_VALUE} if it would positively overflow.
- * @see #convert
* @since 1.6
*/
public long toMinutes(long duration) {
@@ -229,12 +258,12 @@ public enum TimeUnit {
}
/**
- * Equivalent to {@code HOURS.convert(duration, this)}.
+ * Equivalent to
+ * {@link #convert(long, TimeUnit) HOURS.convert(duration, this)}.
* @param duration the duration
* @return the converted duration,
* or {@code Long.MIN_VALUE} if conversion would negatively
* overflow, or {@code Long.MAX_VALUE} if it would positively overflow.
- * @see #convert
* @since 1.6
*/
public long toHours(long duration) {
@@ -242,10 +271,10 @@ public enum TimeUnit {
}
/**
- * Equivalent to {@code DAYS.convert(duration, this)}.
+ * Equivalent to
+ * {@link #convert(long, TimeUnit) DAYS.convert(duration, this)}.
* @param duration the duration
* @return the converted duration
- * @see #convert
* @since 1.6
*/
public long toDays(long duration) {
diff --git a/luni/src/main/java/java/util/concurrent/atomic/AtomicBoolean.java b/luni/src/main/java/java/util/concurrent/atomic/AtomicBoolean.java
index 13b12aa..f51e6af 100644
--- a/luni/src/main/java/java/util/concurrent/atomic/AtomicBoolean.java
+++ b/luni/src/main/java/java/util/concurrent/atomic/AtomicBoolean.java
@@ -5,6 +5,7 @@
*/
package java.util.concurrent.atomic;
+
import sun.misc.Unsafe;
/**
diff --git a/luni/src/main/java/java/util/concurrent/atomic/AtomicInteger.java b/luni/src/main/java/java/util/concurrent/atomic/AtomicInteger.java
index d67b20a..8a15298 100644
--- a/luni/src/main/java/java/util/concurrent/atomic/AtomicInteger.java
+++ b/luni/src/main/java/java/util/concurrent/atomic/AtomicInteger.java
@@ -5,6 +5,7 @@
*/
package java.util.concurrent.atomic;
+
import sun.misc.Unsafe;
/**
diff --git a/luni/src/main/java/java/util/concurrent/atomic/AtomicIntegerArray.java b/luni/src/main/java/java/util/concurrent/atomic/AtomicIntegerArray.java
index 1f6980d..fd492d1 100644
--- a/luni/src/main/java/java/util/concurrent/atomic/AtomicIntegerArray.java
+++ b/luni/src/main/java/java/util/concurrent/atomic/AtomicIntegerArray.java
@@ -5,6 +5,7 @@
*/
package java.util.concurrent.atomic;
+
import sun.misc.Unsafe;
/**
diff --git a/luni/src/main/java/java/util/concurrent/atomic/AtomicIntegerFieldUpdater.java b/luni/src/main/java/java/util/concurrent/atomic/AtomicIntegerFieldUpdater.java
index 6067152..4354cb6 100644
--- a/luni/src/main/java/java/util/concurrent/atomic/AtomicIntegerFieldUpdater.java
+++ b/luni/src/main/java/java/util/concurrent/atomic/AtomicIntegerFieldUpdater.java
@@ -10,6 +10,9 @@ import dalvik.system.VMStack; // android-added
import sun.misc.Unsafe;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
+import java.security.AccessController;
+import java.security.PrivilegedExceptionAction;
+import java.security.PrivilegedActionException;
/**
* A reflection-based utility that enables atomic updates to
@@ -243,7 +246,7 @@ public abstract class AtomicIntegerFieldUpdater<T> {
private final Class<T> tclass;
private final Class<?> cclass;
- AtomicIntegerFieldUpdaterImpl(Class<T> tclass, String fieldName) {
+ AtomicIntegerFieldUpdaterImpl(final Class<T> tclass, final String fieldName) {
final Field field;
final Class<?> caller;
final int modifiers;
diff --git a/luni/src/main/java/java/util/concurrent/atomic/AtomicLong.java b/luni/src/main/java/java/util/concurrent/atomic/AtomicLong.java
index 278c5b5..ab2961a 100644
--- a/luni/src/main/java/java/util/concurrent/atomic/AtomicLong.java
+++ b/luni/src/main/java/java/util/concurrent/atomic/AtomicLong.java
@@ -5,6 +5,7 @@
*/
package java.util.concurrent.atomic;
+
import sun.misc.Unsafe;
/**
diff --git a/luni/src/main/java/java/util/concurrent/atomic/AtomicLongArray.java b/luni/src/main/java/java/util/concurrent/atomic/AtomicLongArray.java
index 2e8c2b7..b7f3d1e 100644
--- a/luni/src/main/java/java/util/concurrent/atomic/AtomicLongArray.java
+++ b/luni/src/main/java/java/util/concurrent/atomic/AtomicLongArray.java
@@ -5,6 +5,7 @@
*/
package java.util.concurrent.atomic;
+
import sun.misc.Unsafe;
/**
diff --git a/luni/src/main/java/java/util/concurrent/atomic/AtomicLongFieldUpdater.java b/luni/src/main/java/java/util/concurrent/atomic/AtomicLongFieldUpdater.java
index 0096a6b..715788c 100644
--- a/luni/src/main/java/java/util/concurrent/atomic/AtomicLongFieldUpdater.java
+++ b/luni/src/main/java/java/util/concurrent/atomic/AtomicLongFieldUpdater.java
@@ -243,7 +243,7 @@ public abstract class AtomicLongFieldUpdater<T> {
private final Class<T> tclass;
private final Class<?> cclass;
- CASUpdater(Class<T> tclass, String fieldName) {
+ CASUpdater(final Class<T> tclass, final String fieldName) {
final Field field;
final Class<?> caller;
final int modifiers;
@@ -337,7 +337,7 @@ public abstract class AtomicLongFieldUpdater<T> {
private final Class<T> tclass;
private final Class<?> cclass;
- LockedUpdater(Class<T> tclass, String fieldName) {
+ LockedUpdater(final Class<T> tclass, final String fieldName) {
Field field = null;
Class<?> caller = null;
int modifiers = 0;
diff --git a/luni/src/main/java/java/util/concurrent/atomic/AtomicMarkableReference.java b/luni/src/main/java/java/util/concurrent/atomic/AtomicMarkableReference.java
index 1257be0..18d148f 100644
--- a/luni/src/main/java/java/util/concurrent/atomic/AtomicMarkableReference.java
+++ b/luni/src/main/java/java/util/concurrent/atomic/AtomicMarkableReference.java
@@ -68,7 +68,7 @@ public class AtomicMarkableReference<V> {
* Typical usage is {@code boolean[1] holder; ref = v.get(holder); }.
*
* @param markHolder an array of size of at least one. On return,
- * {@code markholder[0]} will hold the value of the mark.
+ * {@code markHolder[0]} will hold the value of the mark.
* @return the current value of the reference
*/
public V get(boolean[] markHolder) {
diff --git a/luni/src/main/java/java/util/concurrent/atomic/AtomicReference.java b/luni/src/main/java/java/util/concurrent/atomic/AtomicReference.java
index 98b402a..7ea6066 100644
--- a/luni/src/main/java/java/util/concurrent/atomic/AtomicReference.java
+++ b/luni/src/main/java/java/util/concurrent/atomic/AtomicReference.java
@@ -5,6 +5,7 @@
*/
package java.util.concurrent.atomic;
+
import sun.misc.Unsafe;
/**
diff --git a/luni/src/main/java/java/util/concurrent/atomic/AtomicReferenceFieldUpdater.java b/luni/src/main/java/java/util/concurrent/atomic/AtomicReferenceFieldUpdater.java
index eb2d73e..4b5e59c 100644
--- a/luni/src/main/java/java/util/concurrent/atomic/AtomicReferenceFieldUpdater.java
+++ b/luni/src/main/java/java/util/concurrent/atomic/AtomicReferenceFieldUpdater.java
@@ -5,6 +5,7 @@
*/
package java.util.concurrent.atomic;
+
import dalvik.system.VMStack; // android-added
import sun.misc.Unsafe;
import java.lang.reflect.Field;
@@ -27,7 +28,7 @@ import java.lang.reflect.Modifier;
* private static AtomicReferenceFieldUpdater<Node, Node> rightUpdater =
* AtomicReferenceFieldUpdater.newUpdater(Node.class, Node.class, "right");
*
- * Node getLeft() { return left; }
+ * Node getLeft() { return left; }
* boolean compareAndSetLeft(Node expect, Node update) {
* return leftUpdater.compareAndSet(this, expect, update);
* }
@@ -63,10 +64,11 @@ public abstract class AtomicReferenceFieldUpdater<T,V> {
* or the field is inaccessible to the caller according to Java language
* access control
*/
- public static <U, W> AtomicReferenceFieldUpdater<U,W> newUpdater(Class<U> tclass, Class<W> vclass, String fieldName) {
- return new AtomicReferenceFieldUpdaterImpl<U,W>(tclass,
- vclass,
- fieldName);
+ public static <U,W> AtomicReferenceFieldUpdater<U,W> newUpdater(Class<U> tclass,
+ Class<W> vclass,
+ String fieldName) {
+ return new AtomicReferenceFieldUpdaterImpl<U,W>
+ (tclass, vclass, fieldName);
}
/**
diff --git a/luni/src/main/java/java/util/concurrent/atomic/AtomicStampedReference.java b/luni/src/main/java/java/util/concurrent/atomic/AtomicStampedReference.java
index b93a6f3..1449856 100644
--- a/luni/src/main/java/java/util/concurrent/atomic/AtomicStampedReference.java
+++ b/luni/src/main/java/java/util/concurrent/atomic/AtomicStampedReference.java
@@ -68,7 +68,7 @@ public class AtomicStampedReference<V> {
* Typical usage is {@code int[1] holder; ref = v.get(holder); }.
*
* @param stampHolder an array of size of at least one. On return,
- * {@code stampholder[0]} will hold the value of the stamp.
+ * {@code stampHolder[0]} will hold the value of the stamp.
* @return the current value of the reference
*/
public V get(int[] stampHolder) {
diff --git a/luni/src/main/java/java/util/concurrent/locks/AbstractOwnableSynchronizer.java b/luni/src/main/java/java/util/concurrent/locks/AbstractOwnableSynchronizer.java
index fa01824..66a2f8e 100644
--- a/luni/src/main/java/java/util/concurrent/locks/AbstractOwnableSynchronizer.java
+++ b/luni/src/main/java/java/util/concurrent/locks/AbstractOwnableSynchronizer.java
@@ -35,20 +35,20 @@ public abstract class AbstractOwnableSynchronizer
private transient Thread exclusiveOwnerThread;
/**
- * Sets the thread that currently owns exclusive access. A
- * {@code null} argument indicates that no thread owns access.
+ * Sets the thread that currently owns exclusive access.
+ * A {@code null} argument indicates that no thread owns access.
* This method does not otherwise impose any synchronization or
* {@code volatile} field accesses.
+ * @param thread the owner thread
*/
- protected final void setExclusiveOwnerThread(Thread t) {
- exclusiveOwnerThread = t;
+ protected final void setExclusiveOwnerThread(Thread thread) {
+ exclusiveOwnerThread = thread;
}
/**
- * Returns the thread last set by
- * {@code setExclusiveOwnerThread}, or {@code null} if never
- * set. This method does not otherwise impose any synchronization
- * or {@code volatile} field accesses.
+ * Returns the thread last set by {@code setExclusiveOwnerThread},
+ * or {@code null} if never set. This method does not otherwise
+ * impose any synchronization or {@code volatile} field accesses.
* @return the owner thread
*/
protected final Thread getExclusiveOwnerThread() {
diff --git a/luni/src/main/java/java/util/concurrent/locks/AbstractQueuedLongSynchronizer.java b/luni/src/main/java/java/util/concurrent/locks/AbstractQueuedLongSynchronizer.java
index 37aa9d0..47a02a9 100644
--- a/luni/src/main/java/java/util/concurrent/locks/AbstractQueuedLongSynchronizer.java
+++ b/luni/src/main/java/java/util/concurrent/locks/AbstractQueuedLongSynchronizer.java
@@ -5,6 +5,7 @@
*/
package java.util.concurrent.locks;
+
import java.util.concurrent.TimeUnit;
import java.util.ArrayList;
import java.util.Collection;
@@ -227,7 +228,7 @@ public abstract class AbstractQueuedLongSynchronizer
Node nextWaiter;
/**
- * @return true if node is waiting in shared mode
+ * Returns true if node is waiting in shared mode.
*/
final boolean isShared() {
return nextWaiter == SHARED;
@@ -403,9 +404,9 @@ public abstract class AbstractQueuedLongSynchronizer
Node s = node.next;
if (s == null || s.waitStatus > 0) {
s = null;
- for (Node t = tail; t != null && t != node; t = t.prev)
- if (t.waitStatus <= 0)
- s = t;
+ for (Node p = tail; p != null && p != node; p = p.prev)
+ if (p.waitStatus <= 0)
+ s = p;
}
if (s != null)
LockSupport.unpark(s.thread);
@@ -1397,13 +1398,13 @@ public abstract class AbstractQueuedLongSynchronizer
* @return true if present
*/
private boolean findNodeFromTail(Node node) {
- Node t = tail;
+ Node p = tail;
for (;;) {
- if (t == node)
+ if (p == node)
return true;
- if (t == null)
+ if (p == null)
return false;
- t = t.prev;
+ p = p.prev;
}
}
@@ -1814,6 +1815,7 @@ public abstract class AbstractQueuedLongSynchronizer
throws InterruptedException {
if (Thread.interrupted())
throw new InterruptedException();
+ long initialNanos = nanosTimeout;
Node node = addConditionWaiter();
long savedState = fullyRelease(node);
final long deadline = System.nanoTime() + nanosTimeout;
@@ -1835,7 +1837,8 @@ public abstract class AbstractQueuedLongSynchronizer
unlinkCancelledWaiters();
if (interruptMode != 0)
reportInterruptAfterWait(interruptMode);
- return deadline - System.nanoTime();
+ long remaining = deadline - System.nanoTime(); // avoid overflow
+ return (remaining < initialNanos) ? remaining : Long.MIN_VALUE;
}
/**
@@ -2027,6 +2030,10 @@ public abstract class AbstractQueuedLongSynchronizer
(Node.class.getDeclaredField("next"));
} catch (Exception ex) { throw new Error(ex); }
+
+ // Reduce the risk of rare disastrous classloading in first call to
+ // LockSupport.park: https://bugs.openjdk.java.net/browse/JDK-8074773
+ Class<?> ensureLoaded = LockSupport.class;
}
/**
diff --git a/luni/src/main/java/java/util/concurrent/locks/AbstractQueuedSynchronizer.java b/luni/src/main/java/java/util/concurrent/locks/AbstractQueuedSynchronizer.java
index e711da5..bfe88e5 100644
--- a/luni/src/main/java/java/util/concurrent/locks/AbstractQueuedSynchronizer.java
+++ b/luni/src/main/java/java/util/concurrent/locks/AbstractQueuedSynchronizer.java
@@ -5,6 +5,7 @@
*/
package java.util.concurrent.locks;
+
import java.util.concurrent.TimeUnit;
import java.util.ArrayList;
import java.util.Collection;
@@ -128,15 +129,11 @@ import sun.misc.Unsafe;
* others that are blocked and queued. However, you can, if desired,
* define {@code tryAcquire} and/or {@code tryAcquireShared} to
* disable barging by internally invoking one or more of the inspection
- * methods. In particular, a strict FIFO lock can define
- * {@code tryAcquire} to immediately return {@code false} if {@link
- * #getFirstQueuedThread} does not return the current thread. A
- * normally preferable non-strict fair version can immediately return
- * {@code false} only if {@link #hasQueuedThreads} returns
- * {@code true} and {@code getFirstQueuedThread} is not the current
- * thread; or equivalently, that {@code getFirstQueuedThread} is both
- * non-null and not the current thread. Further variations are
- * possible.
+ * methods, thereby providing a <em>fair</em> FIFO acquisition order.
+ * In particular, most fair synchronizers can define {@code tryAcquire}
+ * to return {@code false} if {@code hasQueuedPredecessors} (a method
+ * specifically designed to be used by fair synchronizers) returns
+ * {@code true}. Other variations are possible.
*
* <p>Throughput and scalability are generally highest for the
* default barging (also known as <em>greedy</em>,
@@ -1461,7 +1458,7 @@ public abstract class AbstractQueuedSynchronizer
* due to the queue being empty.
*
* <p>This method is designed to be used by a fair synchronizer to
- * avoid <a href="AbstractQueuedSynchronizer#barging">barging</a>.
+ * avoid <a href="AbstractQueuedSynchronizer.html#barging">barging</a>.
* Such a synchronizer's {@link #tryAcquire} method should return
* {@code false}, and its {@link #tryAcquireShared} method should
* return a negative value, if this method returns {@code true}
@@ -2042,6 +2039,7 @@ public abstract class AbstractQueuedSynchronizer
throws InterruptedException {
if (Thread.interrupted())
throw new InterruptedException();
+ long initialNanos = nanosTimeout;
Node node = addConditionWaiter();
int savedState = fullyRelease(node);
final long deadline = System.nanoTime() + nanosTimeout;
@@ -2063,7 +2061,8 @@ public abstract class AbstractQueuedSynchronizer
unlinkCancelledWaiters();
if (interruptMode != 0)
reportInterruptAfterWait(interruptMode);
- return deadline - System.nanoTime();
+ long remaining = deadline - System.nanoTime(); // avoid overflow
+ return (remaining < initialNanos) ? remaining : Long.MIN_VALUE;
}
/**
@@ -2255,6 +2254,10 @@ public abstract class AbstractQueuedSynchronizer
(Node.class.getDeclaredField("next"));
} catch (Exception ex) { throw new Error(ex); }
+
+ // Reduce the risk of rare disastrous classloading in first call to
+ // LockSupport.park: https://bugs.openjdk.java.net/browse/JDK-8074773
+ Class<?> ensureLoaded = LockSupport.class;
}
/**
diff --git a/luni/src/main/java/java/util/concurrent/locks/Condition.java b/luni/src/main/java/java/util/concurrent/locks/Condition.java
index 522e9e2..11a7090 100644
--- a/luni/src/main/java/java/util/concurrent/locks/Condition.java
+++ b/luni/src/main/java/java/util/concurrent/locks/Condition.java
@@ -5,6 +5,7 @@
*/
package java.util.concurrent.locks;
+
import java.util.concurrent.TimeUnit;
import java.util.Date;
diff --git a/luni/src/main/java/java/util/concurrent/locks/Lock.java b/luni/src/main/java/java/util/concurrent/locks/Lock.java
index 6eeb236..a7ca001 100644
--- a/luni/src/main/java/java/util/concurrent/locks/Lock.java
+++ b/luni/src/main/java/java/util/concurrent/locks/Lock.java
@@ -5,6 +5,7 @@
*/
package java.util.concurrent.locks;
+
import java.util.concurrent.TimeUnit;
/**
diff --git a/luni/src/main/java/java/util/concurrent/locks/LockSupport.java b/luni/src/main/java/java/util/concurrent/locks/LockSupport.java
index 875b2bf..089d818 100644
--- a/luni/src/main/java/java/util/concurrent/locks/LockSupport.java
+++ b/luni/src/main/java/java/util/concurrent/locks/LockSupport.java
@@ -5,6 +5,7 @@
*/
package java.util.concurrent.locks;
+
import sun.misc.Unsafe;
/**
diff --git a/luni/src/main/java/java/util/concurrent/locks/ReentrantLock.java b/luni/src/main/java/java/util/concurrent/locks/ReentrantLock.java
index bde4741..3654248 100644
--- a/luni/src/main/java/java/util/concurrent/locks/ReentrantLock.java
+++ b/luni/src/main/java/java/util/concurrent/locks/ReentrantLock.java
@@ -5,6 +5,7 @@
*/
package java.util.concurrent.locks;
+
import java.util.concurrent.TimeUnit;
import java.util.Collection;
diff --git a/luni/src/main/java/java/util/concurrent/locks/ReentrantReadWriteLock.java b/luni/src/main/java/java/util/concurrent/locks/ReentrantReadWriteLock.java
index 2d3c65d..cc7ba4c 100644
--- a/luni/src/main/java/java/util/concurrent/locks/ReentrantReadWriteLock.java
+++ b/luni/src/main/java/java/util/concurrent/locks/ReentrantReadWriteLock.java
@@ -5,6 +5,7 @@
*/
package java.util.concurrent.locks;
+
import java.util.concurrent.TimeUnit;
import java.util.Collection;
@@ -236,14 +237,14 @@ public class ReentrantReadWriteLock
static final int MAX_COUNT = (1 << SHARED_SHIFT) - 1;
static final int EXCLUSIVE_MASK = (1 << SHARED_SHIFT) - 1;
- /** Returns the number of shared holds represented in count */
+ /** Returns the number of shared holds represented in count. */
static int sharedCount(int c) { return c >>> SHARED_SHIFT; }
- /** Returns the number of exclusive holds represented in count */
+ /** Returns the number of exclusive holds represented in count. */
static int exclusiveCount(int c) { return c & EXCLUSIVE_MASK; }
/**
* A counter for per-thread read hold counts.
- * Maintained as a ThreadLocal; cached in cachedHoldCounter
+ * Maintained as a ThreadLocal; cached in cachedHoldCounter.
*/
static final class HoldCounter {
int count = 0;
@@ -303,7 +304,7 @@ public class ReentrantReadWriteLock
* <p>This allows tracking of read holds for uncontended read
* locks to be very cheap.
*/
- private transient Thread firstReader = null;
+ private transient Thread firstReader;
private transient int firstReaderHoldCount;
Sync() {
diff --git a/luni/src/main/java/java/util/concurrent/package-info.java b/luni/src/main/java/java/util/concurrent/package-info.java
index 51a29e8..afc8ca4 100644
--- a/luni/src/main/java/java/util/concurrent/package-info.java
+++ b/luni/src/main/java/java/util/concurrent/package-info.java
@@ -4,10 +4,6 @@
* http://creativecommons.org/publicdomain/zero/1.0/
*/
-// BEGIN android-note
-// omit links to ForkJoinPool, ForkJoinTask, LinkedTransferQueue, Phaser, TransferQueue
-// END android-note
-
/**
* Utility classes commonly useful in concurrent programming. This
* package includes a few small standardized extensible frameworks, as
@@ -67,11 +63,20 @@
* assists in coordinating the processing of groups of
* asynchronous tasks.
*
+ * <p>Class {@link java.util.concurrent.ForkJoinPool} provides an
+ * Executor primarily designed for processing instances of {@link
+ * java.util.concurrent.ForkJoinTask} and its subclasses. These
+ * classes employ a work-stealing scheduler that attains high
+ * throughput for tasks conforming to restrictions that often hold in
+ * computation-intensive parallel processing.
+ *
* <h2>Queues</h2>
*
* The {@link java.util.concurrent.ConcurrentLinkedQueue} class
- * supplies an efficient scalable thread-safe non-blocking FIFO
- * queue.
+ * supplies an efficient scalable thread-safe non-blocking FIFO queue.
+ * The {@link java.util.concurrent.ConcurrentLinkedDeque} class is
+ * similar, but additionally supports the {@link java.util.Deque}
+ * interface.
*
* <p>Five implementations in {@code java.util.concurrent} support
* the extended {@link java.util.concurrent.BlockingQueue}
@@ -85,6 +90,12 @@
* for producer-consumer, messaging, parallel tasking, and
* related concurrent designs.
*
+ * <p>Extended interface {@link java.util.concurrent.TransferQueue},
+ * and implementation {@link java.util.concurrent.LinkedTransferQueue}
+ * introduce a synchronous {@code transfer} method (along with related
+ * features) in which a producer may optionally block awaiting its
+ * consumer.
+ *
* <p>The {@link java.util.concurrent.BlockingDeque} interface
* extends {@code BlockingQueue} to support both FIFO and LIFO
* (stack-based) operations.
@@ -111,7 +122,7 @@
*
* <h2>Synchronizers</h2>
*
- * Four classes aid common special-purpose synchronization idioms.
+ * Five classes aid common special-purpose synchronization idioms.
* <ul>
*
* <li>{@link java.util.concurrent.Semaphore} is a classic concurrency tool.
@@ -124,6 +135,10 @@
* multiway synchronization point useful in some styles of parallel
* programming.
*
+ * <li>A {@link java.util.concurrent.Phaser} provides
+ * a more flexible form of barrier that may be used to control phased
+ * computation among multiple threads.
+ *
* <li>An {@link java.util.concurrent.Exchanger} allows two threads to
* exchange objects at a rendezvous point, and is useful in several
* pipeline designs.
@@ -176,7 +191,7 @@
*
* <h2 id="MemoryVisibility">Memory Consistency Properties</h2>
*
- * <a href="http://java.sun.com/docs/books/jls/third_edition/html/memory.html">
+ * <a href="http://docs.oracle.com/javase/specs/jls/se7/html/jls-17.html#jls-17.4.5">
* Chapter 17 of the Java Language Specification</a> defines the
* <i>happens-before</i> relation on memory operations such as reads and
* writes of shared variables. The results of a write by one thread are
@@ -243,7 +258,8 @@
* in each thread <i>happen-before</i> those subsequent to the
* corresponding {@code exchange()} in another thread.
*
- * <li>Actions prior to calling {@code CyclicBarrier.await}
+ * <li>Actions prior to calling {@code CyclicBarrier.await} and
+ * {@code Phaser.awaitAdvance} (as well as its variants)
* <i>happen-before</i> actions performed by the barrier action, and
* actions performed by the barrier action <i>happen-before</i> actions
* subsequent to a successful return from the corresponding {@code await}
diff --git a/luni/src/main/java/java/util/jar/Manifest.java b/luni/src/main/java/java/util/jar/Manifest.java
index 6a3936d..5a6b42d 100644
--- a/luni/src/main/java/java/util/jar/Manifest.java
+++ b/luni/src/main/java/java/util/jar/Manifest.java
@@ -41,8 +41,10 @@ public class Manifest implements Cloneable {
private static final byte[] VALUE_SEPARATOR = new byte[] { ':', ' ' };
- private final Attributes mainAttributes;
- private final HashMap<String, Attributes> entries;
+ /* non-final for {@code #clone()} */
+ private Attributes mainAttributes;
+ /* non-final for {@code #clone()} */
+ private HashMap<String, Attributes> entries;
static final class Chunk {
final int start;
@@ -93,9 +95,7 @@ public class Manifest implements Cloneable {
*/
@SuppressWarnings("unchecked")
public Manifest(Manifest man) {
- mainAttributes = (Attributes) man.mainAttributes.clone();
- entries = (HashMap<String, Attributes>) ((HashMap<String, Attributes>) man
- .getEntries()).clone();
+ cloneAttributesAndEntriesFrom(man);
}
Manifest(byte[] manifestBytes, boolean readChunks) throws IOException {
@@ -156,7 +156,21 @@ public class Manifest implements Cloneable {
*/
@Override
public Object clone() {
- return new Manifest(this);
+ Manifest result;
+ try {
+ result = (Manifest) super.clone();
+ } catch (CloneNotSupportedException e) {
+ throw new AssertionError(e);
+ }
+
+ result.cloneAttributesAndEntriesFrom(this);
+ return result;
+ }
+
+ private final void cloneAttributesAndEntriesFrom(Manifest other) {
+ mainAttributes = (Attributes) other.mainAttributes.clone();
+ entries = (HashMap<String, Attributes>) ((HashMap<String, Attributes>) other
+ .getEntries()).clone();
}
/**
diff --git a/luni/src/main/java/java/util/jar/StrictJarFile.java b/luni/src/main/java/java/util/jar/StrictJarFile.java
index 4a8af5f..a73ca2a 100644
--- a/luni/src/main/java/java/util/jar/StrictJarFile.java
+++ b/luni/src/main/java/java/util/jar/StrictJarFile.java
@@ -24,6 +24,7 @@ import java.io.RandomAccessFile;
import java.security.cert.Certificate;
import java.util.HashMap;
import java.util.Iterator;
+import java.util.Set;
import java.util.zip.Inflater;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
@@ -53,7 +54,7 @@ public final class StrictJarFile {
private final CloseGuard guard = CloseGuard.get();
private boolean closed;
- public StrictJarFile(String fileName) throws IOException {
+ public StrictJarFile(String fileName) throws IOException, SecurityException {
this.nativeHandle = nativeOpenJarFile(fileName);
this.raf = new RandomAccessFile(fileName, "r");
@@ -64,11 +65,18 @@ public final class StrictJarFile {
HashMap<String, byte[]> metaEntries = getMetaEntries();
this.manifest = new Manifest(metaEntries.get(JarFile.MANIFEST_NAME), true);
this.verifier = new JarVerifier(fileName, manifest, metaEntries);
+ Set<String> files = this.manifest.getEntries().keySet();
+ for (String file : files) {
+ if (findEntry(file) == null) {
+ throw new SecurityException(fileName + ": File " + file + " in manifest does not exist");
+ }
+ }
isSigned = verifier.readCertificates() && verifier.isSignedJar();
- } catch (IOException ioe) {
+ } catch (IOException | SecurityException e) {
nativeClose(this.nativeHandle);
- throw ioe;
+ IoUtils.closeQuietly(this.raf);
+ throw e;
}
guard.open("close");
diff --git a/luni/src/main/java/java/util/logging/FileHandler.java b/luni/src/main/java/java/util/logging/FileHandler.java
index 6ffef87..1fd1dbf 100644
--- a/luni/src/main/java/java/util/logging/FileHandler.java
+++ b/luni/src/main/java/java/util/logging/FileHandler.java
@@ -261,15 +261,15 @@ public class FileHandler extends StreamHandler {
boolean hasUniqueID = false;
boolean hasGeneration = false;
- // TODO privilege code?
+ String homePath = System.getProperty("user.home");
+ if (homePath == null) {
+ throw new NullPointerException("System property \"user.home\" is null");
+ }
+ boolean homePathHasSepEnd = homePath.endsWith(File.separator);
String tempPath = System.getProperty("java.io.tmpdir");
- boolean tempPathHasSepEnd = (tempPath == null ? false : tempPath
- .endsWith(File.separator));
-
- String homePath = System.getProperty("user.home");
- boolean homePathHasSepEnd = (homePath == null ? false : homePath
- .endsWith(File.separator));
+ tempPath = tempPath == null ? homePath : tempPath;
+ boolean tempPathHasSepEnd = tempPath.endsWith(File.separator);
StringBuilder sb = new StringBuilder();
pattern = pattern.replace('/', File.separatorChar);
diff --git a/luni/src/main/java/java/util/logging/SocketHandler.java b/luni/src/main/java/java/util/logging/SocketHandler.java
index 48bfc0e..5de847a 100644
--- a/luni/src/main/java/java/util/logging/SocketHandler.java
+++ b/luni/src/main/java/java/util/logging/SocketHandler.java
@@ -17,6 +17,7 @@
package java.util.logging;
+import libcore.net.NetworkSecurityPolicy;
import java.io.BufferedOutputStream;
import java.io.IOException;
import java.net.Socket;
@@ -106,14 +107,21 @@ public class SocketHandler extends StreamHandler {
throw new IllegalArgumentException("host == null || host.isEmpty()");
}
// check the validity of the port number
- int p = 0;
+ int p;
try {
p = Integer.parsePositiveInt(port);
+ // Must be >= 0 to get this far. 0 is invalid too.
+ if (p == 0) {
+ throw new IllegalArgumentException("Illegal port argument " + port);
+ }
} catch (NumberFormatException e) {
throw new IllegalArgumentException("Illegal port argument " + port);
}
// establish the network connection
try {
+ if (!NetworkSecurityPolicy.isCleartextTrafficPermitted()) {
+ throw new IOException("Cleartext traffic not permitted");
+ }
this.socket = new Socket(host, p);
} catch (IOException e) {
getErrorManager().error("Failed to establish the network connection", e,
diff --git a/luni/src/main/java/java/util/logging/XMLFormatter.java b/luni/src/main/java/java/util/logging/XMLFormatter.java
index 0d80b3e..3952596 100644
--- a/luni/src/main/java/java/util/logging/XMLFormatter.java
+++ b/luni/src/main/java/java/util/logging/XMLFormatter.java
@@ -17,6 +17,7 @@
package java.util.logging;
+import java.io.IOException;
import java.text.MessageFormat;
import java.util.Date;
import java.util.ResourceBundle;
@@ -50,7 +51,7 @@ public class XMLFormatter extends Formatter {
// call a method of LogRecord to ensure not null
long time = r.getMillis();
// format to date
- String date = MessageFormat.format("{0, date} {0, time}", new Object[] { new Date(time) });
+ String date = MessageFormat.format("{0, date} {0, time}", new Date(time));
String nl = System.lineSeparator();
StringBuilder sb = new StringBuilder();
@@ -59,21 +60,21 @@ public class XMLFormatter extends Formatter {
append(sb, 1, "millis", time);
append(sb, 1, "sequence", r.getSequenceNumber());
if (r.getLoggerName() != null) {
- append(sb, 1, "logger", r.getLoggerName());
+ escapeAndAppend(sb, 1, "logger", r.getLoggerName());
}
append(sb, 1, "level", r.getLevel().getName());
if (r.getSourceClassName() != null) {
append(sb, 1, "class", r.getSourceClassName());
}
if (r.getSourceMethodName() != null) {
- append(sb, 1, "method", r.getSourceMethodName());
+ escapeAndAppend(sb, 1, "method", r.getSourceMethodName());
}
append(sb, 1, "thread", r.getThreadID());
formatMessages(r, sb);
Object[] params = r.getParameters();
if (params != null) {
for (Object element : params) {
- append(sb, 1, "param", element);
+ escapeAndAppend(sb, 1, "param", element);
}
}
formatThrowable(r, sb);
@@ -96,14 +97,14 @@ public class XMLFormatter extends Formatter {
if (message == null) {
message = pattern;
- append(sb, 1, "message", message);
+ escapeAndAppend(sb, 1, "message", message);
} else {
- append(sb, 1, "message", message);
- append(sb, 1, "key", pattern);
- append(sb, 1, "catalog", r.getResourceBundleName());
+ escapeAndAppend(sb, 1, "message", message);
+ escapeAndAppend(sb, 1, "key", pattern);
+ escapeAndAppend(sb, 1, "catalog", r.getResourceBundleName());
}
} else if (pattern != null) {
- append(sb, 1, "message", pattern);
+ escapeAndAppend(sb, 1, "message", pattern);
} else {
sb.append(indent).append("<message/>");
}
@@ -114,13 +115,13 @@ public class XMLFormatter extends Formatter {
if ((t = r.getThrown()) != null) {
String nl = System.lineSeparator();
sb.append(indent).append("<exception>").append(nl);
- append(sb, 2, "message", t.toString());
+ escapeAndAppend(sb, 2, "message", t.toString());
// format throwable's stack trace
StackTraceElement[] elements = t.getStackTrace();
for (StackTraceElement e : elements) {
sb.append(indent).append(indent).append("<frame>").append(nl);
append(sb, 3, "class", e.getClassName());
- append(sb, 3, "method", e.getMethodName());
+ escapeAndAppend(sb, 3, "method", e.getMethodName());
append(sb, 3, "line", e.getLineNumber());
sb.append(indent).append(indent).append("</frame>").append(nl);
}
@@ -138,6 +139,49 @@ public class XMLFormatter extends Formatter {
sb.append(System.lineSeparator());
}
+ private static void escapeAndAppend(StringBuilder sb, int indentCount, String tag, Object value) {
+ if (value == null) {
+ append(sb, indentCount, tag, value);
+ } else {
+ for (int i = 0; i < indentCount; ++i) {
+ sb.append(indent);
+ }
+ sb.append("<").append(tag).append(">");
+ try {
+ escapeXml(sb, value.toString());
+ } catch (IOException e) {
+ throw new AssertionError();
+ }
+ sb.append("</").append(tag).append(">");
+ sb.append(System.lineSeparator());
+ }
+ }
+
+ private static void escapeXml(Appendable valueBuilder, String value) throws IOException {
+ for (int i = 0; i < value.length(); i++) {
+ char c = value.charAt(i);
+ switch (c) {
+ case '\"':
+ valueBuilder.append("&quot;");
+ break;
+ case '>':
+ valueBuilder.append("&gt;");
+ break;
+ case '<':
+ valueBuilder.append("&lt;");
+ break;
+ case '&':
+ valueBuilder.append("&amp;");
+ break;
+ case '\'':
+ valueBuilder.append("&apos;");
+ break;
+ default:
+ valueBuilder.append(c);
+ }
+ }
+ }
+
/**
* Returns the header string for a set of log records formatted as XML
* strings, using the output handler's encoding if it is defined, otherwise
diff --git a/luni/src/main/java/java/util/zip/GZIPInputStream.java b/luni/src/main/java/java/util/zip/GZIPInputStream.java
index 1bfc496..925e8c4 100644
--- a/luni/src/main/java/java/util/zip/GZIPInputStream.java
+++ b/luni/src/main/java/java/util/zip/GZIPInputStream.java
@@ -222,7 +222,7 @@ public class GZIPInputStream extends InflaterInputStream {
if (hcrc) {
crc.update(header, 0, 2);
}
- int length = Memory.peekShort(scratch, 0, ByteOrder.LITTLE_ENDIAN) & 0xffff;
+ int length = Memory.peekShort(header, 0, ByteOrder.LITTLE_ENDIAN) & 0xffff;
while (length > 0) {
int max = length > scratch.length ? scratch.length : length;
int result = in.read(scratch, 0, max);
@@ -243,7 +243,7 @@ public class GZIPInputStream extends InflaterInputStream {
}
if (hcrc) {
Streams.readFully(in, header, 0, 2);
- short crc16 = Memory.peekShort(scratch, 0, ByteOrder.LITTLE_ENDIAN);
+ short crc16 = Memory.peekShort(header, 0, ByteOrder.LITTLE_ENDIAN);
if ((short) crc.getValue() != crc16) {
throw new IOException("CRC mismatch");
}
diff --git a/luni/src/main/java/java/util/zip/Zip64.java b/luni/src/main/java/java/util/zip/Zip64.java
new file mode 100644
index 0000000..3060670
--- /dev/null
+++ b/luni/src/main/java/java/util/zip/Zip64.java
@@ -0,0 +1,415 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package java.util.zip;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.RandomAccessFile;
+import java.nio.BufferOverflowException;
+import java.nio.BufferUnderflowException;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+
+import static java.util.zip.ZipOutputStream.writeIntAsUint16;
+import static java.util.zip.ZipOutputStream.writeLongAsUint32;
+import static java.util.zip.ZipOutputStream.writeLongAsUint64;
+
+/**
+ * @hide
+ */
+public class Zip64 {
+
+ /* Non instantiable */
+ private Zip64() {}
+
+ /**
+ * The maximum supported entry / archive size for standard (non zip64) entries and archives.
+ *
+ * @hide
+ */
+ public static final long MAX_ZIP_ENTRY_AND_ARCHIVE_SIZE = 0x00000000ffffffffL;
+
+ /**
+ * The header ID of the zip64 extended info header. This value is used to identify
+ * zip64 data in the "extra" field in the file headers.
+ */
+ private static final short ZIP64_EXTENDED_INFO_HEADER_ID = 0x0001;
+
+
+ /*
+ * Size (in bytes) of the zip64 end of central directory locator. This will be located
+ * immediately before the end of central directory record if a given zipfile is in the
+ * zip64 format.
+ */
+ private static final int ZIP64_LOCATOR_SIZE = 20;
+
+ /**
+ * The zip64 end of central directory locator signature (4 bytes wide).
+ */
+ private static final int ZIP64_LOCATOR_SIGNATURE = 0x07064b50;
+
+ /**
+ * The zip64 end of central directory record singature (4 bytes wide).
+ */
+ private static final int ZIP64_EOCD_RECORD_SIGNATURE = 0x06064b50;
+
+ /**
+ * The "effective" size of the zip64 eocd record. This excludes the fields that
+ * are proprietary, signature, or fields we aren't interested in. We include the
+ * following (contiguous) fields in this calculation :
+ * - disk number (4 bytes)
+ * - disk with start of central directory (4 bytes)
+ * - number of central directory entries on this disk (8 bytes)
+ * - total number of central directory entries (8 bytes)
+ * - size of the central directory (8 bytes)
+ * - offset of the start of the central directory (8 bytes)
+ */
+ private static final int ZIP64_EOCD_RECORD_EFFECTIVE_SIZE = 40;
+
+ /**
+ * Parses the zip64 end of central directory record locator. The locator
+ * must be placed immediately before the end of central directory (eocd) record
+ * starting at {@code eocdOffset}.
+ *
+ * The position of the file cursor for {@code raf} after a call to this method
+ * is undefined an callers must reposition it after each call to this method.
+ */
+ public static long parseZip64EocdRecordLocator(RandomAccessFile raf, long eocdOffset)
+ throws IOException {
+ // The spec stays curiously silent about whether a zip file with an EOCD record,
+ // a zip64 locator and a zip64 eocd record is considered "empty". In our implementation,
+ // we parse all records and read the counts from them instead of drawing any size or
+ // layout based information.
+ if (eocdOffset > ZIP64_LOCATOR_SIZE) {
+ raf.seek(eocdOffset - ZIP64_LOCATOR_SIZE);
+ if (Integer.reverseBytes(raf.readInt()) == ZIP64_LOCATOR_SIGNATURE) {
+ byte[] zip64EocdLocator = new byte[ZIP64_LOCATOR_SIZE - 4];
+ raf.readFully(zip64EocdLocator);
+ ByteBuffer buf = ByteBuffer.wrap(zip64EocdLocator).order(ByteOrder.LITTLE_ENDIAN);
+
+ final int diskWithCentralDir = buf.getInt();
+ final long zip64EocdRecordOffset = buf.getLong();
+ final int numDisks = buf.getInt();
+
+ if (numDisks != 1 || diskWithCentralDir != 0) {
+ throw new ZipException("Spanned archives not supported");
+ }
+
+ return zip64EocdRecordOffset;
+ }
+ }
+
+ return -1;
+ }
+
+ public static ZipFile.EocdRecord parseZip64EocdRecord(RandomAccessFile raf,
+ long eocdRecordOffset, int commentLength) throws IOException {
+ raf.seek(eocdRecordOffset);
+ final int signature = Integer.reverseBytes(raf.readInt());
+ if (signature != ZIP64_EOCD_RECORD_SIGNATURE) {
+ throw new ZipException("Invalid zip64 eocd record offset, sig="
+ + Integer.toHexString(signature) + " offset=" + eocdRecordOffset);
+ }
+
+ // The zip64 eocd record specifies its own size as an 8 byte integral type. It is variable
+ // length because of the "zip64 extensible data sector" but that field is reserved for
+ // pkware's proprietary use. We therefore disregard it altogether and treat the end of
+ // central directory structure as fixed length.
+ //
+ // We also skip "version made by" (2 bytes) and "version needed to extract" (2 bytes)
+ // fields. We perform additional validation at the ZipEntry level, where applicable.
+ //
+ // That's a total of 12 bytes to skip
+ raf.skipBytes(12);
+
+ byte[] zip64Eocd = new byte[ZIP64_EOCD_RECORD_EFFECTIVE_SIZE];
+ raf.readFully(zip64Eocd);
+
+ ByteBuffer buf = ByteBuffer.wrap(zip64Eocd).order(ByteOrder.LITTLE_ENDIAN);
+ try {
+ int diskNumber = buf.getInt();
+ int diskWithCentralDirStart = buf.getInt();
+ long numEntries = buf.getLong();
+ long totalNumEntries = buf.getLong();
+ buf.getLong(); // Ignore the size of the central directory
+ long centralDirOffset = buf.getLong();
+
+ if (numEntries != totalNumEntries || diskNumber != 0 || diskWithCentralDirStart != 0) {
+ throw new ZipException("Spanned archives not supported :" +
+ " numEntries=" + numEntries + ", totalNumEntries=" + totalNumEntries +
+ ", diskNumber=" + diskNumber + ", diskWithCentralDirStart=" +
+ diskWithCentralDirStart);
+ }
+
+ return new ZipFile.EocdRecord(numEntries, centralDirOffset, commentLength);
+ } catch (BufferUnderflowException bue) {
+ ZipException zipException = new ZipException("Error parsing zip64 eocd record.");
+ zipException.initCause(bue);
+ throw zipException;
+ }
+ }
+
+ /**
+ * Parse the zip64 extended info record from the extras present in {@code ze}.
+ *
+ * If {@code fromCentralDirectory} is true, we assume we're parsing a central directory
+ * record. We assume a local file header otherwise. The difference between the two is that
+ * a central directory entry is required to be complete, whereas a local file header isn't.
+ * This is due to the presence of an optional data descriptor after the file content.
+ *
+ * @return {@code} true iff. a zip64 extended info record was found.
+ */
+ public static boolean parseZip64ExtendedInfo(ZipEntry ze, boolean fromCentralDirectory)
+ throws ZipException {
+ int extendedInfoSize = -1;
+ int extendedInfoStart = -1;
+ // If this file contains a zip64 central directory locator, entries might
+ // optionally contain a zip64 extended information extra entry.
+ if (ze.extra != null && ze.extra.length > 0) {
+ // Extensible data fields are of the form header1+data1 + header2+data2 and so
+ // on, where each header consists of a 2 byte header ID followed by a 2 byte size.
+ // We need to iterate through the entire list of headers to find the header ID
+ // for the zip64 extended information extra field (0x0001).
+ final ByteBuffer buf = ByteBuffer.wrap(ze.extra).order(ByteOrder.LITTLE_ENDIAN);
+ extendedInfoSize = getZip64ExtendedInfoSize(buf);
+ if (extendedInfoSize != -1) {
+ extendedInfoStart = buf.position();
+ try {
+ // The size & compressed size only make sense in the central directory *or* if
+ // we know them beforehand. If we don't know them beforehand, they're stored in
+ // the data descriptor and should be read from there.
+ //
+ // Note that the spec says that the local file header "MUST" contain the
+ // original and compressed size fields. We don't care too much about that.
+ // The spec claims that the order of fields is fixed anyway.
+ if (fromCentralDirectory || (ze.getMethod() == ZipEntry.STORED)) {
+ if (ze.size == MAX_ZIP_ENTRY_AND_ARCHIVE_SIZE) {
+ ze.size = buf.getLong();
+ }
+
+ if (ze.compressedSize == MAX_ZIP_ENTRY_AND_ARCHIVE_SIZE) {
+ ze.compressedSize = buf.getLong();
+ }
+ }
+
+ // The local header offset is significant only in the central directory. It makes no
+ // sense within the local header itself.
+ if (fromCentralDirectory) {
+ if (ze.localHeaderRelOffset == MAX_ZIP_ENTRY_AND_ARCHIVE_SIZE) {
+ ze.localHeaderRelOffset = buf.getLong();
+ }
+ }
+ } catch (BufferUnderflowException bue) {
+ ZipException zipException = new ZipException("Error parsing extended info");
+ zipException.initCause(bue);
+ throw zipException;
+ }
+ }
+ }
+
+ // This entry doesn't contain a zip64 extended information data entry header.
+ // We have to check that the compressedSize / size / localHeaderRelOffset values
+ // are valid and don't require the presence of the extended header.
+ if (extendedInfoSize == -1) {
+ if (ze.compressedSize == MAX_ZIP_ENTRY_AND_ARCHIVE_SIZE ||
+ ze.size == MAX_ZIP_ENTRY_AND_ARCHIVE_SIZE ||
+ ze.localHeaderRelOffset == MAX_ZIP_ENTRY_AND_ARCHIVE_SIZE) {
+ throw new ZipException("File contains no zip64 extended information: "
+ + "name=" + ze.name + "compressedSize=" + ze.compressedSize + ", size="
+ + ze.size + ", localHeader=" + ze.localHeaderRelOffset);
+ }
+
+ return false;
+ } else {
+ // If we're parsed the zip64 extended info header, we remove it from the extras
+ // so that applications that set their own extras will see the data they set.
+
+ // This is an unfortunate workaround needed due to a gap in the spec. The spec demands
+ // that extras are present in the "extensible" format, which means that each extra field
+ // must be prefixed with a header ID and a length. However, earlier versions of the spec
+ // made no mention of this, nor did any existing API enforce it. This means users could
+ // set "free form" extras without caring very much whether the implementation wanted to
+ // extend or add to them.
+
+ // The start of the extended info header.
+ final int extendedInfoHeaderStart = extendedInfoStart - 4;
+ // The total size of the extended info, including the header.
+ final int extendedInfoTotalSize = extendedInfoSize + 4;
+
+ final int extrasLen = ze.extra.length - extendedInfoTotalSize;
+ byte[] extrasWithoutZip64 = new byte[extrasLen];
+
+ System.arraycopy(ze.extra, 0, extrasWithoutZip64, 0, extendedInfoHeaderStart);
+ System.arraycopy(ze.extra, extendedInfoHeaderStart + extendedInfoTotalSize,
+ extrasWithoutZip64, extendedInfoHeaderStart, (extrasLen - extendedInfoHeaderStart));
+
+ ze.extra = extrasWithoutZip64;
+ return true;
+ }
+ }
+
+ /**
+ * Appends a zip64 extended info record to the extras contained in {@code ze}. If {@code ze}
+ * contains no extras, a new extras array is created.
+ */
+ public static void insertZip64ExtendedInfoToExtras(ZipEntry ze) throws ZipException {
+ final byte[] output;
+ // We always write the size, uncompressed size and local rel header offset in all our
+ // Zip64 extended info headers (in both the local file header as well as the central
+ // directory). We always omit the disk number because we don't support spanned
+ // archives anyway.
+ //
+ // 2 bytes : Zip64 Extended Info Header ID
+ // 2 bytes : Zip64 Extended Info Field Size.
+ // 8 bytes : Uncompressed size
+ // 8 bytes : Compressed size
+ // 8 bytes : Local header rel offset.
+ // ----------
+ // 28 bytes : total
+ final int extendedInfoSize = 28;
+
+ if (ze.extra == null) {
+ output = new byte[extendedInfoSize];
+ } else {
+ // If the existing extras are already too big, we have no choice but to throw
+ // an error.
+ if (ze.extra.length + extendedInfoSize > 65535) {
+ throw new ZipException("No space in extras for zip64 extended entry info");
+ }
+
+ // We copy existing extras over and put the zip64 extended info at the beginning. This
+ // is to avoid breakages in the presence of "old style" extras which don't contain
+ // headers and lengths. The spec is again silent about these inconsistencies.
+ //
+ // This means that people that for ZipOutputStream users, the value ZipEntry.getExtra
+ // after an entry is written will be different from before. This shouldn't be an issue
+ // in practice.
+ output = new byte[ze.extra.length + extendedInfoSize];
+ System.arraycopy(ze.extra, 0, output, extendedInfoSize, ze.extra.length);
+ }
+
+ ByteBuffer bb = ByteBuffer.wrap(output).order(ByteOrder.LITTLE_ENDIAN);
+ bb.putShort(ZIP64_EXTENDED_INFO_HEADER_ID);
+ // We subtract four because extendedInfoSize includes the ID and field
+ // size itself.
+ bb.putShort((short) (extendedInfoSize - 4));
+
+ if (ze.getMethod() == ZipEntry.STORED) {
+ bb.putLong(ze.size);
+ bb.putLong(ze.compressedSize);
+ } else {
+ // Store these fields in the data descriptor instead.
+ bb.putLong(0); // size.
+ bb.putLong(0); // compressed size.
+ }
+
+ // The offset is only relevant in the central directory entry, but we write it out here
+ // anyway, since we know what it is.
+ bb.putLong(ze.localHeaderRelOffset);
+
+ ze.extra = output;
+ }
+
+ /**
+ * Returns the size of the extended info record if {@code extras} contains a zip64 extended info
+ * record, {@code -1} otherwise. The buffer will be positioned at the start of the extended info
+ * record.
+ */
+ private static int getZip64ExtendedInfoSize(ByteBuffer extras) {
+ try {
+ while (extras.hasRemaining()) {
+ final int headerId = extras.getShort() & 0xffff;
+ final int length = extras.getShort() & 0xffff;
+ if (headerId == ZIP64_EXTENDED_INFO_HEADER_ID) {
+ if (extras.remaining() >= length) {
+ return length;
+ } else {
+ return -1;
+ }
+ } else {
+ extras.position(extras.position() + length);
+ }
+ }
+
+ return -1;
+ } catch (BufferUnderflowException bue) {
+ // We'll underflow if we have an incomplete header in our extras.
+ return -1;
+ } catch (IllegalArgumentException iae) {
+ // ByteBuffer.position() will throw if we have a truncated extra or
+ // an invalid length in the header.
+ return -1;
+ }
+ }
+
+ /**
+ * Copy the size, compressed size and local header offset fields from {@code ze} to
+ * inside {@code ze}'s extended info record. This is additional step is necessary when
+ * we could calculate the correct sizes only after writing out the entry. In this case,
+ * the local file header would not contain real sizes, and they would be present in the
+ * data descriptor and the central directory only.
+ *
+ * We choose the simplest strategy of always writing out the size, compressedSize and
+ * local header offset in all our Zip64 Extended info records.
+ */
+ public static void refreshZip64ExtendedInfo(ZipEntry ze) {
+ if (ze.extra == null) {
+ throw new IllegalStateException("Zip64 entry has no available extras: " + ze);
+ }
+
+ ByteBuffer buf = ByteBuffer.wrap(ze.extra).order(ByteOrder.LITTLE_ENDIAN);
+ final int extendedInfoSize = getZip64ExtendedInfoSize(buf);
+ if (extendedInfoSize == -1) {
+ throw new IllegalStateException(
+ "Zip64 entry extras has no zip64 extended info record: " + ze);
+ }
+
+ try {
+ buf.putLong(ze.size);
+ buf.putLong(ze.compressedSize);
+ buf.putLong(ze.localHeaderRelOffset);
+ } catch (BufferOverflowException boe) {
+ throw new IllegalStateException("Invalid extended info extra", boe);
+ }
+ }
+
+ public static void writeZip64EocdRecordAndLocator(ByteArrayOutputStream baos,
+ long numEntries, long offset, long cDirSize) throws IOException {
+ // Step 1: Write out the zip64 EOCD record.
+ writeLongAsUint32(baos, ZIP64_EOCD_RECORD_SIGNATURE);
+ // The size of the zip64 eocd record. This is the effective size + the
+ // size of the "version made by" (2 bytes) and the "version needed to extract" (2 bytes)
+ // fields.
+ writeLongAsUint64(baos, ZIP64_EOCD_RECORD_EFFECTIVE_SIZE + 4);
+ // TODO: What values should we put here ? The pre-zip64 values we've chosen don't
+ // seem to make much sense either.
+ writeIntAsUint16(baos, 20);
+ writeIntAsUint16(baos, 20);
+ writeLongAsUint32(baos, 0L); // number of disk
+ writeLongAsUint32(baos, 0L); // number of disk with start of central dir.
+ writeLongAsUint64(baos, numEntries); // number of entries in this disk.
+ writeLongAsUint64(baos, numEntries); // number of entries in total.
+ writeLongAsUint64(baos, cDirSize); // size of the central directory.
+ writeLongAsUint64(baos, offset); // offset of the central directory wrt. this file.
+
+ // Step 2: Write out the zip64 EOCD record locator.
+ writeLongAsUint32(baos, ZIP64_LOCATOR_SIGNATURE);
+ writeLongAsUint32(baos, 0); // number of disk with start of central dir.
+ writeLongAsUint64(baos, offset + cDirSize); // offset of the eocd record wrt. this file.
+ writeLongAsUint32(baos, 1); // total number of disks.
+ }
+}
diff --git a/luni/src/main/java/java/util/zip/ZipEntry.java b/luni/src/main/java/java/util/zip/ZipEntry.java
index 217cc3c..a06f1b6 100644
--- a/luni/src/main/java/java/util/zip/ZipEntry.java
+++ b/luni/src/main/java/java/util/zip/ZipEntry.java
@@ -52,7 +52,6 @@ public class ZipEntry implements ZipConstants, Cloneable {
byte[] extra;
- int nameLength = -1;
long localHeaderRelOffset = -1;
long dataOffset = -1;
@@ -67,9 +66,10 @@ public class ZipEntry implements ZipConstants, Cloneable {
*/
public static final int STORED = 0;
- ZipEntry(String name, String comment, long crc, long compressedSize,
+ /** @hide - for testing only */
+ public ZipEntry(String name, String comment, long crc, long compressedSize,
long size, int compressionMethod, int time, int modDate, byte[] extra,
- int nameLength, long localHeaderRelOffset, long dataOffset) {
+ long localHeaderRelOffset, long dataOffset) {
this.name = name;
this.comment = comment;
this.crc = crc;
@@ -79,7 +79,6 @@ public class ZipEntry implements ZipConstants, Cloneable {
this.time = time;
this.modDate = modDate;
this.extra = extra;
- this.nameLength = nameLength;
this.localHeaderRelOffset = localHeaderRelOffset;
this.dataOffset = dataOffset;
}
@@ -149,6 +148,11 @@ public class ZipEntry implements ZipConstants, Cloneable {
/**
* Gets the name of this {@code ZipEntry}.
*
+ * <p><em>Security note:</em> Entry names can represent relative paths. {@code foo/../bar} or
+ * {@code ../bar/baz}, for example. If the entry name is being used to construct a filename
+ * or as a path component, it must be validated or sanitized to ensure that files are not
+ * written outside of the intended destination directory.
+ *
* @return the entry name.
*/
public String getName() {
@@ -265,17 +269,15 @@ public class ZipEntry implements ZipConstants, Cloneable {
/**
* Sets the uncompressed size of this {@code ZipEntry}.
*
- * @param value
- * the uncompressed size for this entry.
- * @throws IllegalArgumentException
- * if {@code value} < 0 or {@code value} > 0xFFFFFFFFL.
+ * @param value the uncompressed size for this entry.
+ * @throws IllegalArgumentException if {@code value < 0}.
*/
public void setSize(long value) {
- if (value >= 0 && value <= 0xFFFFFFFFL) {
- size = value;
- } else {
+ if (value < 0) {
throw new IllegalArgumentException("Bad size: " + value);
}
+
+ size = value;
}
/**
@@ -340,7 +342,6 @@ public class ZipEntry implements ZipConstants, Cloneable {
compressionMethod = ze.compressionMethod;
modDate = ze.modDate;
extra = ze.extra;
- nameLength = ze.nameLength;
localHeaderRelOffset = ze.localHeaderRelOffset;
dataOffset = ze.dataOffset;
}
@@ -378,7 +379,7 @@ public class ZipEntry implements ZipConstants, Cloneable {
* On exit, "in" will be positioned at the start of the next entry
* in the Central Directory.
*/
- ZipEntry(byte[] cdeHdrBuf, InputStream cdStream, Charset defaultCharset) throws IOException {
+ ZipEntry(byte[] cdeHdrBuf, InputStream cdStream, Charset defaultCharset, boolean isZip64) throws IOException {
Streams.readFully(cdStream, cdeHdrBuf, 0, cdeHdrBuf.length);
BufferIterator it = HeapBufferIterator.iterator(cdeHdrBuf, 0, cdeHdrBuf.length,
@@ -412,7 +413,7 @@ public class ZipEntry implements ZipConstants, Cloneable {
compressedSize = ((long) it.readInt()) & 0xffffffffL;
size = ((long) it.readInt()) & 0xffffffffL;
- nameLength = it.readShort() & 0xffff;
+ int nameLength = it.readShort() & 0xffff;
int extraLength = it.readShort() & 0xffff;
int commentByteCount = it.readShort() & 0xffff;
@@ -437,6 +438,10 @@ public class ZipEntry implements ZipConstants, Cloneable {
Streams.readFully(cdStream, commentBytes, 0, commentByteCount);
comment = new String(commentBytes, 0, commentBytes.length, charset);
}
+
+ if (isZip64) {
+ Zip64.parseZip64ExtendedInfo(this, true /* from central directory */);
+ }
}
private static boolean containsNulByte(byte[] bytes) {
diff --git a/luni/src/main/java/java/util/zip/ZipFile.java b/luni/src/main/java/java/util/zip/ZipFile.java
index b44156e..307e7fe 100644
--- a/luni/src/main/java/java/util/zip/ZipFile.java
+++ b/luni/src/main/java/java/util/zip/ZipFile.java
@@ -107,6 +107,18 @@ public class ZipFile implements Closeable, ZipConstants {
private final CloseGuard guard = CloseGuard.get();
+ static class EocdRecord {
+ final long numEntries;
+ final long centralDirOffset;
+ final int commentLength;
+
+ EocdRecord(long numEntries, long centralDirOffset, int commentLength) {
+ this.numEntries = numEntries;
+ this.centralDirOffset = centralDirOffset;
+ this.commentLength = commentLength;
+ }
+ }
+
/**
* Constructs a new {@code ZipFile} allowing read access to the contents of the given file.
*
@@ -390,9 +402,11 @@ public class ZipFile implements Closeable, ZipConstants {
stopOffset = 0;
}
+ long eocdOffset;
while (true) {
raf.seek(scanOffset);
if (Integer.reverseBytes(raf.readInt()) == ENDSIG) {
+ eocdOffset = scanOffset;
break;
}
@@ -402,41 +416,35 @@ public class ZipFile implements Closeable, ZipConstants {
}
}
- // Read the End Of Central Directory. ENDHDR includes the signature bytes,
- // which we've already read.
- byte[] eocd = new byte[ENDHDR - 4];
- raf.readFully(eocd);
+ final long zip64EocdRecordOffset = Zip64.parseZip64EocdRecordLocator(raf, eocdOffset);
- // Pull out the information we need.
- BufferIterator it = HeapBufferIterator.iterator(eocd, 0, eocd.length, ByteOrder.LITTLE_ENDIAN);
- int diskNumber = it.readShort() & 0xffff;
- int diskWithCentralDir = it.readShort() & 0xffff;
- int numEntries = it.readShort() & 0xffff;
- int totalNumEntries = it.readShort() & 0xffff;
- it.skip(4); // Ignore centralDirSize.
- long centralDirOffset = ((long) it.readInt()) & 0xffffffffL;
- int commentLength = it.readShort() & 0xffff;
-
- if (numEntries != totalNumEntries || diskNumber != 0 || diskWithCentralDir != 0) {
- throw new ZipException("Spanned archives not supported");
- }
-
- if (commentLength > 0) {
- byte[] commentBytes = new byte[commentLength];
+ // Seek back past the eocd signature so that we can continue with our search.
+ // Note that we add 4 bytes to the offset to skip past the signature.
+ EocdRecord record = parseEocdRecord(raf, eocdOffset + 4, (zip64EocdRecordOffset != -1) /* isZip64 */);
+ // Read the comment now to avoid an additional seek. We also know the commentLength
+ // won't change because that information isn't present in the zip64 eocd record.
+ if (record.commentLength > 0) {
+ byte[] commentBytes = new byte[record.commentLength];
raf.readFully(commentBytes);
comment = new String(commentBytes, 0, commentBytes.length, StandardCharsets.UTF_8);
}
+ // We have a zip64 eocd record : use that for getting the information we need.
+ if (zip64EocdRecordOffset != -1) {
+ record = Zip64.parseZip64EocdRecord(raf, zip64EocdRecordOffset, record.commentLength);
+ }
+
// Seek to the first CDE and read all entries.
// We have to do this now (from the constructor) rather than lazily because the
// public API doesn't allow us to throw IOException except from the constructor
// or from getInputStream.
- RAFStream rafStream = new RAFStream(raf, centralDirOffset);
+ RAFStream rafStream = new RAFStream(raf, record.centralDirOffset);
BufferedInputStream bufferedStream = new BufferedInputStream(rafStream, 4096);
byte[] hdrBuf = new byte[CENHDR]; // Reuse the same buffer for each entry.
- for (int i = 0; i < numEntries; ++i) {
- ZipEntry newEntry = new ZipEntry(hdrBuf, bufferedStream, StandardCharsets.UTF_8);
- if (newEntry.localHeaderRelOffset >= centralDirOffset) {
+ for (long i = 0; i < record.numEntries; ++i) {
+ ZipEntry newEntry = new ZipEntry(hdrBuf, bufferedStream, StandardCharsets.UTF_8,
+ (zip64EocdRecordOffset != -1) /* isZip64 */);
+ if (newEntry.localHeaderRelOffset >= record.centralDirOffset) {
throw new ZipException("Local file header offset is after central directory");
}
String entryName = newEntry.getName();
@@ -446,6 +454,45 @@ public class ZipFile implements Closeable, ZipConstants {
}
}
+ private static EocdRecord parseEocdRecord(RandomAccessFile raf, long offset, boolean isZip64) throws IOException {
+ raf.seek(offset);
+
+ // Read the End Of Central Directory. ENDHDR includes the signature bytes,
+ // which we've already read.
+ byte[] eocd = new byte[ENDHDR - 4];
+ raf.readFully(eocd);
+
+ BufferIterator it = HeapBufferIterator.iterator(eocd, 0, eocd.length, ByteOrder.LITTLE_ENDIAN);
+ final long numEntries;
+ final long centralDirOffset;
+ if (isZip64) {
+ numEntries = -1;
+ centralDirOffset = -1;
+
+ // If we have a zip64 end of central directory record, we skip through the regular
+ // end of central directory record and use the information from the zip64 eocd record.
+ // We're still forced to read the comment length (below) since it isn't present in the
+ // zip64 eocd record.
+ it.skip(16);
+ } else {
+ // If we don't have a zip64 eocd record, we read values from the "regular"
+ // eocd record.
+ int diskNumber = it.readShort() & 0xffff;
+ int diskWithCentralDir = it.readShort() & 0xffff;
+ numEntries = it.readShort() & 0xffff;
+ int totalNumEntries = it.readShort() & 0xffff;
+ it.skip(4); // Ignore centralDirSize.
+
+ centralDirOffset = ((long) it.readInt()) & 0xffffffffL;
+ if (numEntries != totalNumEntries || diskNumber != 0 || diskWithCentralDir != 0) {
+ throw new ZipException("Spanned archives not supported");
+ }
+ }
+
+ final int commentLength = it.readShort() & 0xffff;
+ return new EocdRecord(numEntries, centralDirOffset, commentLength);
+ }
+
static void throwZipException(String msg, int magic) throws ZipException {
final String hexString = IntegralToString.intToHexString(magic, true, 8);
throw new ZipException(msg + " signature not found; was " + hexString);
diff --git a/luni/src/main/java/java/util/zip/ZipInputStream.java b/luni/src/main/java/java/util/zip/ZipInputStream.java
index 4c0034e..f3ca74e 100644
--- a/luni/src/main/java/java/util/zip/ZipInputStream.java
+++ b/luni/src/main/java/java/util/zip/ZipInputStream.java
@@ -81,7 +81,9 @@ public class ZipInputStream extends InflaterInputStream implements ZipConstants
private ZipEntry currentEntry;
- private final byte[] hdrBuf = new byte[LOCHDR - LOCVER];
+ private boolean currentEntryIsZip64;
+
+ private final byte[] hdrBuf = new byte[LOCHDR - LOCVER + 8];
private final CRC32 crc = new CRC32();
@@ -159,7 +161,7 @@ public class ZipInputStream extends InflaterInputStream implements ZipConstants
}
try {
- readAndVerifyDataDescriptor(inB, out);
+ readAndVerifyDataDescriptor(inB, out, currentEntryIsZip64);
} catch (Exception e) {
if (failure == null) { // otherwise we're already going to throw
failure = e;
@@ -183,16 +185,31 @@ public class ZipInputStream extends InflaterInputStream implements ZipConstants
}
}
- private void readAndVerifyDataDescriptor(int inB, int out) throws IOException {
+ private void readAndVerifyDataDescriptor(long inB, long out, boolean isZip64) throws IOException {
if (hasDD) {
- Streams.readFully(in, hdrBuf, 0, EXTHDR);
+ if (isZip64) {
+ // 8 additional bytes since the compressed / uncompressed size fields
+ // in the extended header are 8 bytes each, instead of 4 bytes each.
+ Streams.readFully(in, hdrBuf, 0, EXTHDR + 8);
+ } else {
+ Streams.readFully(in, hdrBuf, 0, EXTHDR);
+ }
+
int sig = Memory.peekInt(hdrBuf, 0, ByteOrder.LITTLE_ENDIAN);
if (sig != (int) EXTSIG) {
throw new ZipException(String.format("unknown format (EXTSIG=%x)", sig));
}
currentEntry.crc = ((long) Memory.peekInt(hdrBuf, EXTCRC, ByteOrder.LITTLE_ENDIAN)) & 0xffffffffL;
- currentEntry.compressedSize = ((long) Memory.peekInt(hdrBuf, EXTSIZ, ByteOrder.LITTLE_ENDIAN)) & 0xffffffffL;
- currentEntry.size = ((long) Memory.peekInt(hdrBuf, EXTLEN, ByteOrder.LITTLE_ENDIAN)) & 0xffffffffL;
+
+ if (isZip64) {
+ currentEntry.compressedSize = Memory.peekLong(hdrBuf, EXTSIZ, ByteOrder.LITTLE_ENDIAN);
+ // Note that we apply an adjustment of 4 bytes to the offset of EXTLEN to account
+ // for the 8 byte size for zip64.
+ currentEntry.size = Memory.peekLong(hdrBuf, EXTLEN + 4, ByteOrder.LITTLE_ENDIAN);
+ } else {
+ currentEntry.compressedSize = ((long) Memory.peekInt(hdrBuf, EXTSIZ, ByteOrder.LITTLE_ENDIAN)) & 0xffffffffL;
+ currentEntry.size = ((long) Memory.peekInt(hdrBuf, EXTLEN, ByteOrder.LITTLE_ENDIAN)) & 0xffffffffL;
+ }
}
if (currentEntry.crc != crc.getValue()) {
throw new ZipException("CRC mismatch");
@@ -266,7 +283,11 @@ public class ZipInputStream extends InflaterInputStream implements ZipConstants
byte[] extraData = new byte[extraLength];
Streams.readFully(in, extraData, 0, extraLength);
currentEntry.setExtra(extraData);
+ currentEntryIsZip64 = Zip64.parseZip64ExtendedInfo(currentEntry, false /* from central directory */);
+ } else {
+ currentEntryIsZip64 = false;
}
+
return currentEntry;
}
diff --git a/luni/src/main/java/java/util/zip/ZipOutputStream.java b/luni/src/main/java/java/util/zip/ZipOutputStream.java
index 8278355..dfd85b6 100644
--- a/luni/src/main/java/java/util/zip/ZipOutputStream.java
+++ b/luni/src/main/java/java/util/zip/ZipOutputStream.java
@@ -23,6 +23,8 @@ import java.io.OutputStream;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.HashSet;
+
+import libcore.util.CountingOutputStream;
import libcore.util.EmptyArray;
/**
@@ -85,7 +87,7 @@ public class ZipOutputStream extends DeflaterOutputStream implements ZipConstant
private final CRC32 crc = new CRC32();
- private int offset = 0, curOffset = 0;
+ private long offset = 0;
/** The charset-encoded name for the current entry. */
private byte[] nameBytes;
@@ -93,6 +95,31 @@ public class ZipOutputStream extends DeflaterOutputStream implements ZipConstant
/** The charset-encoded comment for the current entry. */
private byte[] entryCommentBytes;
+ private static final byte[] ZIP64_PLACEHOLDER_BYTES =
+ new byte[] { (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff };
+
+ /**
+ * Whether this zip file needs a Zip64 EOCD record / zip64 EOCD record locator. This
+ * will be true if we wrote an entry whose size or compressed size was too large for
+ * the standard zip format or if we exceeded the maximum number of entries allowed
+ * in the standard format.
+ */
+ private boolean archiveNeedsZip64EocdRecord;
+
+ /**
+ * Whether the current entry being processed needs a zip64 extended info record. This
+ * will be true if the entry is too large for the standard zip format or if the offset
+ * to the start of the current entry header is greater than 0xFFFFFFFF.
+ */
+ private boolean currentEntryNeedsZip64;
+
+ /**
+ * Whether we force all entries in this archive to have a zip64 extended info record.
+ * This of course implies that the {@code currentEntryNeedsZip64} and
+ * {@code archiveNeedsZip64EocdRecord} are always {@code true}.
+ */
+ private final boolean forceZip64;
+
/**
* Constructs a new {@code ZipOutputStream} that writes a zip file to the given
* {@code OutputStream}.
@@ -100,7 +127,15 @@ public class ZipOutputStream extends DeflaterOutputStream implements ZipConstant
* <p>UTF-8 will be used to encode the file comment, entry names and comments.
*/
public ZipOutputStream(OutputStream os) {
- super(os, new Deflater(Deflater.DEFAULT_COMPRESSION, true));
+ this(os, false /* forceZip64 */);
+ }
+
+ /**
+ * @hide for testing only.
+ */
+ public ZipOutputStream(OutputStream os, boolean forceZip64) {
+ super(new CountingOutputStream(os), new Deflater(Deflater.DEFAULT_COMPRESSION, true));
+ this.forceZip64 = forceZip64;
}
/**
@@ -146,15 +181,30 @@ public class ZipOutputStream extends DeflaterOutputStream implements ZipConstant
throw new ZipException("Size mismatch");
}
}
- curOffset = LOCHDR;
+
+ long curOffset = LOCHDR;
// Write the DataDescriptor
if (currentEntry.getMethod() != STORED) {
curOffset += EXTHDR;
- writeLong(out, EXTSIG);
- writeLong(out, currentEntry.crc = crc.getValue());
- writeLong(out, currentEntry.compressedSize = def.getTotalOut());
- writeLong(out, currentEntry.size = def.getTotalIn());
+
+ // Data descriptor signature and CRC are 4 bytes each for both zip and zip64.
+ writeLongAsUint32(out, EXTSIG);
+ writeLongAsUint32(out, currentEntry.crc = crc.getValue());
+
+ currentEntry.compressedSize = def.getBytesWritten();
+ currentEntry.size = def.getBytesRead();
+
+ if (currentEntryNeedsZip64) {
+ // We need an additional 8 bytes to store 8 byte compressed / uncompressed
+ // sizes.
+ curOffset += 8;
+ writeLongAsUint64(out, currentEntry.compressedSize);
+ writeLongAsUint64(out, currentEntry.size);
+ } else {
+ writeLongAsUint32(out, currentEntry.compressedSize);
+ writeLongAsUint32(out, currentEntry.size);
+ }
}
// Update the CentralDirectory
// http://www.pkware.com/documents/casestudies/APPNOTE.TXT
@@ -163,33 +213,58 @@ public class ZipOutputStream extends DeflaterOutputStream implements ZipConstant
// Some tools insist that the central directory have the UTF-8 flag.
// http://code.google.com/p/android/issues/detail?id=20214
flags |= ZipFile.GPBF_UTF8_FLAG;
- writeLong(cDir, CENSIG);
- writeShort(cDir, ZIP_VERSION_2_0); // Version this file was made by.
- writeShort(cDir, ZIP_VERSION_2_0); // Minimum version needed to extract.
- writeShort(cDir, flags);
- writeShort(cDir, currentEntry.getMethod());
- writeShort(cDir, currentEntry.time);
- writeShort(cDir, currentEntry.modDate);
- writeLong(cDir, crc.getValue());
+ writeLongAsUint32(cDir, CENSIG);
+ writeIntAsUint16(cDir, ZIP_VERSION_2_0); // Version this file was made by.
+ writeIntAsUint16(cDir, ZIP_VERSION_2_0); // Minimum version needed to extract.
+ writeIntAsUint16(cDir, flags);
+ writeIntAsUint16(cDir, currentEntry.getMethod());
+ writeIntAsUint16(cDir, currentEntry.time);
+ writeIntAsUint16(cDir, currentEntry.modDate);
+ writeLongAsUint32(cDir, crc.getValue());
+
if (currentEntry.getMethod() == DEFLATED) {
- curOffset += writeLong(cDir, def.getTotalOut());
- writeLong(cDir, def.getTotalIn());
+ currentEntry.setCompressedSize(def.getBytesWritten());
+ currentEntry.setSize(def.getBytesRead());
+ curOffset += currentEntry.getCompressedSize();
+ } else {
+ currentEntry.setCompressedSize(crc.tbytes);
+ currentEntry.setSize(crc.tbytes);
+ curOffset += currentEntry.getSize();
+ }
+
+ if (currentEntryNeedsZip64) {
+ // Refresh the extended info with the compressed size / size before
+ // writing it to the central directory.
+ Zip64.refreshZip64ExtendedInfo(currentEntry);
+
+ // NOTE: We would've written out the zip64 extended info locator to the entry
+ // extras while constructing the local file header. There's no need to do it again
+ // here. If we do, there will be a size mismatch since we're calculating offsets
+ // based on the *current* size of the extra data and not based on the size
+ // at the point of writing the LFH.
+ writeLongAsUint32(cDir, Zip64.MAX_ZIP_ENTRY_AND_ARCHIVE_SIZE);
+ writeLongAsUint32(cDir, Zip64.MAX_ZIP_ENTRY_AND_ARCHIVE_SIZE);
} else {
- curOffset += writeLong(cDir, crc.tbytes);
- writeLong(cDir, crc.tbytes);
+ writeLongAsUint32(cDir, currentEntry.getCompressedSize());
+ writeLongAsUint32(cDir, currentEntry.getSize());
}
- curOffset += writeShort(cDir, nameBytes.length);
+
+ curOffset += writeIntAsUint16(cDir, nameBytes.length);
if (currentEntry.extra != null) {
- curOffset += writeShort(cDir, currentEntry.extra.length);
+ curOffset += writeIntAsUint16(cDir, currentEntry.extra.length);
} else {
- writeShort(cDir, 0);
+ writeIntAsUint16(cDir, 0);
}
- writeShort(cDir, entryCommentBytes.length); // Comment length.
- writeShort(cDir, 0); // Disk Start
- writeShort(cDir, 0); // Internal File Attributes
- writeLong(cDir, 0); // External File Attributes
- writeLong(cDir, offset);
+ writeIntAsUint16(cDir, entryCommentBytes.length); // Comment length.
+ writeIntAsUint16(cDir, 0); // Disk Start
+ writeIntAsUint16(cDir, 0); // Internal File Attributes
+ writeLongAsUint32(cDir, 0); // External File Attributes
+ if (currentEntryNeedsZip64) {
+ writeLongAsUint32(cDir, Zip64.MAX_ZIP_ENTRY_AND_ARCHIVE_SIZE);
+ } else {
+ writeLongAsUint32(cDir, currentEntry.localHeaderRelOffset);
+ }
cDir.write(nameBytes);
nameBytes = null;
if (currentEntry.extra != null) {
@@ -228,16 +303,32 @@ public class ZipOutputStream extends DeflaterOutputStream implements ZipConstant
if (currentEntry != null) {
closeEntry();
}
- int cdirSize = cDir.size();
+
+ int cdirEntriesSize = cDir.size();
+ if (archiveNeedsZip64EocdRecord) {
+ Zip64.writeZip64EocdRecordAndLocator(cDir, entries.size(), offset, cdirEntriesSize);
+ }
+
// Write Central Dir End
- writeLong(cDir, ENDSIG);
- writeShort(cDir, 0); // Disk Number
- writeShort(cDir, 0); // Start Disk
- writeShort(cDir, entries.size()); // Number of entries
- writeShort(cDir, entries.size()); // Number of entries
- writeLong(cDir, cdirSize); // Size of central dir
- writeLong(cDir, offset); // Offset of central dir
- writeShort(cDir, commentBytes.length);
+ writeLongAsUint32(cDir, ENDSIG);
+ writeIntAsUint16(cDir, 0); // Disk Number
+ writeIntAsUint16(cDir, 0); // Start Disk
+
+ // Instead of trying to figure out *why* this archive needed a zip64 eocd record,
+ // just delegate all these values to the zip64 eocd record.
+ if (archiveNeedsZip64EocdRecord) {
+ writeIntAsUint16(cDir, 0xFFFF); // Number of entries
+ writeIntAsUint16(cDir, 0xFFFF); // Number of entries
+ writeLongAsUint32(cDir, 0xFFFFFFFF); // Size of central dir
+ writeLongAsUint32(cDir, 0xFFFFFFFF); // Offset of central dir;
+ } else {
+ writeIntAsUint16(cDir, entries.size()); // Number of entries
+ writeIntAsUint16(cDir, entries.size()); // Number of entries
+ writeLongAsUint32(cDir, cdirEntriesSize); // Size of central dir
+ writeLongAsUint32(cDir, offset); // Offset of central dir
+ }
+
+ writeIntAsUint16(cDir, commentBytes.length);
if (commentBytes.length > 0) {
cDir.write(commentBytes);
}
@@ -288,14 +379,8 @@ public class ZipOutputStream extends DeflaterOutputStream implements ZipConstant
}
checkOpen();
+ checkAndSetZip64Requirements(ze);
- if (entries.contains(ze.name)) {
- throw new ZipException("Entry already exists: " + ze.name);
- }
- if (entries.size() == 64*1024-1) {
- // TODO: support Zip64.
- throw new ZipException("Too many entries for the zip file format's 16-bit entry count");
- }
nameBytes = ze.name.getBytes(StandardCharsets.UTF_8);
checkSizeIsWithinShort("Name", nameBytes);
entryCommentBytes = EmptyArray.BYTE;
@@ -310,6 +395,7 @@ public class ZipOutputStream extends DeflaterOutputStream implements ZipConstant
ze.setMethod(method);
currentEntry = ze;
+ currentEntry.localHeaderRelOffset = offset;
entries.add(currentEntry.name);
// Local file header.
@@ -318,30 +404,48 @@ public class ZipOutputStream extends DeflaterOutputStream implements ZipConstant
// Java always outputs UTF-8 filenames. (Before Java 7, the RI didn't set this flag and used
// modified UTF-8. From Java 7, when using UTF_8 it sets this flag and uses normal UTF-8.)
flags |= ZipFile.GPBF_UTF8_FLAG;
- writeLong(out, LOCSIG); // Entry header
- writeShort(out, ZIP_VERSION_2_0); // Minimum version needed to extract.
- writeShort(out, flags);
- writeShort(out, method);
+ writeLongAsUint32(out, LOCSIG); // Entry header
+ writeIntAsUint16(out, ZIP_VERSION_2_0); // Minimum version needed to extract.
+ writeIntAsUint16(out, flags);
+ writeIntAsUint16(out, method);
if (currentEntry.getTime() == -1) {
currentEntry.setTime(System.currentTimeMillis());
}
- writeShort(out, currentEntry.time);
- writeShort(out, currentEntry.modDate);
+ writeIntAsUint16(out, currentEntry.time);
+ writeIntAsUint16(out, currentEntry.modDate);
if (method == STORED) {
- writeLong(out, currentEntry.crc);
- writeLong(out, currentEntry.size);
- writeLong(out, currentEntry.size);
+ writeLongAsUint32(out, currentEntry.crc);
+
+ if (currentEntryNeedsZip64) {
+ // NOTE: According to the spec, we're allowed to use these fields under zip64
+ // as long as the sizes are <= 4G (and omit writing the zip64 extended information header).
+ //
+ // For simplicity, we write the zip64 extended info here even if we only need it
+ // in the central directory (i.e, the case where we're turning on zip64 because the
+ // offset to this entries LFH is > 0xFFFFFFFF).
+ out.write(ZIP64_PLACEHOLDER_BYTES); // compressed size
+ out.write(ZIP64_PLACEHOLDER_BYTES); // uncompressed size
+ } else {
+ writeLongAsUint32(out, currentEntry.size);
+ writeLongAsUint32(out, currentEntry.size);
+ }
} else {
- writeLong(out, 0);
- writeLong(out, 0);
- writeLong(out, 0);
+ writeLongAsUint32(out, 0);
+ writeLongAsUint32(out, 0);
+ writeLongAsUint32(out, 0);
+ }
+
+ writeIntAsUint16(out, nameBytes.length);
+
+ if (currentEntryNeedsZip64) {
+ Zip64.insertZip64ExtendedInfoToExtras(currentEntry);
}
- writeShort(out, nameBytes.length);
+
if (currentEntry.extra != null) {
- writeShort(out, currentEntry.extra.length);
+ writeIntAsUint16(out, currentEntry.extra.length);
} else {
- writeShort(out, 0);
+ writeIntAsUint16(out, 0);
}
out.write(nameBytes);
if (currentEntry.extra != null) {
@@ -349,6 +453,37 @@ public class ZipOutputStream extends DeflaterOutputStream implements ZipConstant
}
}
+ private void checkAndSetZip64Requirements(ZipEntry entry) {
+ final long totalBytesWritten = getBytesWritten();
+ final long entriesWritten = entries.size();
+
+ currentEntryNeedsZip64 = false;
+ if (forceZip64) {
+ currentEntryNeedsZip64 = true;
+ archiveNeedsZip64EocdRecord = true;
+ return;
+ }
+
+ // In this particular case, we'll write a zip64 eocd record locator and a zip64 eocd
+ // record but we won't actually need zip64 extended info records for any of the individual
+ // entries (unless they trigger the checks below).
+ if (entriesWritten == 64*1024 - 1) {
+ archiveNeedsZip64EocdRecord = true;
+ }
+
+ // Check whether we'll need to write out a zip64 extended info record in both the local file header
+ // and the central directory. In addition, we will need a zip64 eocd record locator
+ // and record to mark this archive as zip64.
+ //
+ // TODO: This is an imprecise check. When method != STORED it's possible that the compressed
+ // size will be (slightly) larger than the actual size. How can we improve this ?
+ if (totalBytesWritten > Zip64.MAX_ZIP_ENTRY_AND_ARCHIVE_SIZE ||
+ (entry.getSize() > Zip64.MAX_ZIP_ENTRY_AND_ARCHIVE_SIZE)) {
+ currentEntryNeedsZip64 = true;
+ archiveNeedsZip64EocdRecord = true;
+ }
+ }
+
/**
* Sets the comment associated with the file being written. See {@link ZipFile#getComment}.
* @throws IllegalArgumentException if the comment is >= 64 Ki encoded bytes.
@@ -386,7 +521,7 @@ public class ZipOutputStream extends DeflaterOutputStream implements ZipConstant
defaultCompressionMethod = method;
}
- private long writeLong(OutputStream os, long i) throws IOException {
+ static long writeLongAsUint32(OutputStream os, long i) throws IOException {
// Write out the long value as an unsigned int
os.write((int) (i & 0xFF));
os.write((int) (i >> 8) & 0xFF);
@@ -395,7 +530,23 @@ public class ZipOutputStream extends DeflaterOutputStream implements ZipConstant
return i;
}
- private int writeShort(OutputStream os, int i) throws IOException {
+ static long writeLongAsUint64(OutputStream os, long i) throws IOException {
+ int i1 = (int) i;
+ os.write(i1 & 0xFF);
+ os.write((i1 >> 8) & 0xFF);
+ os.write((i1 >> 16) & 0xFF);
+ os.write((i1 >> 24) & 0xFF);
+
+ int i2 = (int) (i >> 32);
+ os.write(i2 & 0xFF);
+ os.write((i2 >> 8) & 0xFF);
+ os.write((i2 >> 16) & 0xFF);
+ os.write((i2 >> 24) & 0xFF);
+
+ return i;
+ }
+
+ static int writeIntAsUint16(OutputStream os, int i) throws IOException {
os.write(i & 0xFF);
os.write((i >> 8) & 0xFF);
return i;
@@ -414,6 +565,13 @@ public class ZipOutputStream extends DeflaterOutputStream implements ZipConstant
throw new ZipException("No active entry");
}
+ final long totalBytes = crc.tbytes + byteCount;
+ if ((totalBytes > Zip64.MAX_ZIP_ENTRY_AND_ARCHIVE_SIZE) && !currentEntryNeedsZip64) {
+ throw new IOException("Zip entry size (" + totalBytes +
+ " bytes) cannot be represented in the zip format (needs Zip64)." +
+ " Set the entry length using ZipEntry#setLength to use Zip64 where necessary.");
+ }
+
if (currentEntry.getMethod() == STORED) {
out.write(buffer, offset, byteCount);
} else {
@@ -434,4 +592,11 @@ public class ZipOutputStream extends DeflaterOutputStream implements ZipConstant
" bytes");
}
}
+
+ private long getBytesWritten() {
+ // This cast is somewhat messy but less error prone than keeping an
+ // CountingOutputStream reference around in addition to the FilterOutputStream's
+ // out.
+ return ((CountingOutputStream) out).getCount();
+ }
}
diff --git a/luni/src/main/java/javax/crypto/Cipher.java b/luni/src/main/java/javax/crypto/Cipher.java
index 2e3b341..b27ea88 100644
--- a/luni/src/main/java/javax/crypto/Cipher.java
+++ b/luni/src/main/java/javax/crypto/Cipher.java
@@ -108,6 +108,50 @@ public class Cipher {
};
/**
+ * Used to keep track of which underlying {@code CipherSpi#engineInit(...)}
+ * variant to call when testing suitability.
+ */
+ private static enum InitType {
+ KEY, ALGORITHM_PARAMS, ALGORITHM_PARAM_SPEC,
+ };
+
+ /**
+ * Keeps track of the possible arguments to {@code Cipher#init(...)}.
+ */
+ private static class InitParams {
+ private final InitType initType;
+ private final int opmode;
+ private final Key key;
+ private final SecureRandom random;
+ private final AlgorithmParameterSpec spec;
+ private final AlgorithmParameters params;
+
+ private InitParams(InitType initType, int opmode, Key key, SecureRandom random,
+ AlgorithmParameterSpec spec, AlgorithmParameters params) {
+ this.initType = initType;
+ this.opmode = opmode;
+ this.key = key;
+ this.random = random;
+ this.spec = spec;
+ this.params = params;
+ }
+ }
+
+ /**
+ * Expresses the various types of transforms that may be used during
+ * initialization.
+ */
+ private static class Transform {
+ private final String name;
+ private final NeedToSet needToSet;
+
+ public Transform(String name, NeedToSet needToSet) {
+ this.name = name;
+ this.needToSet = needToSet;
+ }
+ }
+
+ /**
* The service name.
*/
private static final String SERVICE = "Cipher";
@@ -297,7 +341,16 @@ public class Cipher {
}
String[] transformParts = checkTransformation(transformation);
- if (tryCombinations(null, provider, transformParts) == null) {
+
+ Engine.SpiAndProvider sap;
+ try {
+ sap = tryCombinations(null /* params */, provider, transformation, transformParts);
+ } catch (InvalidKeyException | InvalidAlgorithmParameterException e) {
+ // should never happen since we passed in null params
+ throw new ProviderException(e);
+ }
+
+ if (sap == null) {
if (provider == null) {
throw new NoSuchAlgorithmException("No provider found for " + transformation);
} else {
@@ -308,6 +361,25 @@ public class Cipher {
return new Cipher(transformation, transformParts, provider);
}
+ /**
+ * Checks that the provided algorithm {@code transformation} string is a
+ * valid input. The algorithm is the only mandatory field and input can be
+ * of the form:
+ * <ul>
+ * <li><code>"[cipher]"</code>
+ * <li><code>"[cipher]/[mode]/[padding]"</code>
+ * <li><code>"[cipher]//[padding]"</code>
+ * <li><code>"[cipher]/[mode]"</code>
+ * </ul>
+ * <p>
+ * Returns the specified transformation split up into three parts
+ * corresponding to their function:
+ * <p>
+ * <code>
+ * {&lt;algorithm&gt;, &lt;mode&gt;, &lt;padding&gt;}
+ * </code>
+ * <p>
+ */
private static String[] checkTransformation(String transformation)
throws NoSuchAlgorithmException {
// ignore an extra prefix / characters such as in
@@ -339,22 +411,33 @@ public class Cipher {
}
/**
- * Makes sure a CipherSpi that matches this type is selected.
+ * Makes sure a CipherSpi that matches this type is selected. If
+ * {@code key != null} then it assumes that a suitable provider exists for
+ * this instance (used by {@link #init}. If the {@code initParams} is passed
+ * in, then the {@code CipherSpi} returned will be initialized.
+ *
+ * @throws InvalidKeyException if the specified key cannot be used to
+ * initialize this cipher.
+ * @throws InvalidAlgorithmParameterException
*/
- private CipherSpi getSpi(Key key) {
+ private CipherSpi getSpi(InitParams initParams) throws InvalidKeyException,
+ InvalidAlgorithmParameterException {
if (specifiedSpi != null) {
return specifiedSpi;
}
synchronized (initLock) {
- if (spiImpl != null && key == null) {
+ // This is not only a matter of performance. Many methods like update, doFinal, etc.
+ // call {@code #getSpi()} (ie, {@code #getSpi(null /* params */)}) and without this
+ // shortcut they would override an spi that was chosen using the key.
+ if (spiImpl != null && initParams == null) {
return spiImpl;
}
- final Engine.SpiAndProvider sap = tryCombinations(key, specifiedProvider,
- transformParts);
+ final Engine.SpiAndProvider sap = tryCombinations(initParams, specifiedProvider,
+ transformation, transformParts);
if (sap == null) {
- throw new ProviderException("No provider for " + transformation);
+ throw new ProviderException("No provider found for " + transformation);
}
spiImpl = (CipherSpi) sap.spi;
@@ -368,79 +451,130 @@ public class Cipher {
* Convenience call when the Key is not available.
*/
private CipherSpi getSpi() {
- return getSpi(null);
+ try {
+ return getSpi(null);
+ } catch (InvalidKeyException | InvalidAlgorithmParameterException e) {
+ throw new ProviderException("Exception thrown when params == null", e);
+ }
}
/**
- * Try all combinations of mode strings:
+ * Returns the {@code CipherSpi} backing this {@code Cipher} or {@code null} if no
+ * {@code CipherSpi} is backing this {@code Cipher}.
*
- * <pre>
- * [cipher]/[mode]/[padding]
- * [cipher]/[mode]
- * [cipher]//[padding]
- * [cipher]
- * </pre>
+ * @hide
*/
- private static Engine.SpiAndProvider tryCombinations(Key key, Provider provider,
- String[] transformParts) {
- Engine.SpiAndProvider sap = null;
+ public CipherSpi getCurrentSpi() {
+ if (specifiedSpi != null) {
+ return specifiedSpi;
+ }
- if (transformParts[1] != null && transformParts[2] != null) {
- sap = tryTransform(key, provider, transformParts[0] + "/" + transformParts[1] + "/"
- + transformParts[2], transformParts, NeedToSet.NONE);
- if (sap != null) {
- return sap;
- }
+ synchronized (initLock) {
+ return spiImpl;
}
+ }
+ /**
+ * Tries to find the correct {@code Cipher} transform to use. Returns a
+ * {@link Engine.SpiAndProvider}, throws the first exception that was
+ * encountered during attempted initialization, or {@code null} if there are
+ * no providers that support the {@code initParams}.
+ * <p>
+ * {@code transformParts} must be in the format returned by
+ * {@link #checkTransformation(String)}. The combinations of mode strings
+ * tried are as follows:
+ * <ul>
+ * <li><code>[cipher]/[mode]/[padding]</code>
+ * <li><code>[cipher]/[mode]</code>
+ * <li><code>[cipher]//[padding]</code>
+ * <li><code>[cipher]</code>
+ * </ul>
+ */
+ private static Engine.SpiAndProvider tryCombinations(InitParams initParams, Provider provider,
+ String transformation, String[] transformParts) throws InvalidKeyException,
+ InvalidAlgorithmParameterException {
+ // Enumerate all the transforms we need to try
+ ArrayList<Transform> transforms = new ArrayList<Transform>();
+ if (transformParts[1] != null && transformParts[2] != null) {
+ transforms.add(new Transform(transformParts[0] + "/" + transformParts[1] + "/"
+ + transformParts[2], NeedToSet.NONE));
+ }
if (transformParts[1] != null) {
- sap = tryTransform(key, provider, transformParts[0] + "/" + transformParts[1],
- transformParts, NeedToSet.PADDING);
- if (sap != null) {
- return sap;
- }
+ transforms.add(new Transform(transformParts[0] + "/" + transformParts[1],
+ NeedToSet.PADDING));
}
-
if (transformParts[2] != null) {
- sap = tryTransform(key, provider, transformParts[0] + "//" + transformParts[2],
- transformParts, NeedToSet.MODE);
- if (sap != null) {
- return sap;
+ transforms.add(new Transform(transformParts[0] + "//" + transformParts[2],
+ NeedToSet.MODE));
+ }
+ transforms.add(new Transform(transformParts[0], NeedToSet.BOTH));
+
+ // Try each of the transforms and keep track of the first exception
+ // encountered.
+ Exception cause = null;
+ for (Transform transform : transforms) {
+ if (provider != null) {
+ Provider.Service service = provider.getService(SERVICE, transform.name);
+ if (service == null) {
+ continue;
+ }
+ return tryTransformWithProvider(initParams, transformParts, transform.needToSet,
+ service);
}
- }
-
- return tryTransform(key, provider, transformParts[0], transformParts, NeedToSet.BOTH);
- }
-
- private static Engine.SpiAndProvider tryTransform(Key key, Provider provider, String transform,
- String[] transformParts, NeedToSet type) {
- if (provider != null) {
- Provider.Service service = provider.getService(SERVICE, transform);
- if (service == null) {
- return null;
+ ArrayList<Provider.Service> services = ENGINE.getServices(transform.name);
+ if (services == null || services.isEmpty()) {
+ continue;
+ }
+ for (Provider.Service service : services) {
+ if (initParams == null || initParams.key == null
+ || service.supportsParameter(initParams.key)) {
+ try {
+ Engine.SpiAndProvider sap = tryTransformWithProvider(initParams,
+ transformParts, transform.needToSet, service);
+ if (sap != null) {
+ return sap;
+ }
+ } catch (Exception e) {
+ if (cause == null) {
+ cause = e;
+ }
+ }
+ }
}
- return tryTransformWithProvider(key, transformParts, type, service);
}
- ArrayList<Provider.Service> services = ENGINE.getServices(transform);
- if (services == null) {
+ if (cause instanceof InvalidKeyException) {
+ throw (InvalidKeyException) cause;
+ } else if (cause instanceof InvalidAlgorithmParameterException) {
+ throw (InvalidAlgorithmParameterException) cause;
+ } else if (cause instanceof RuntimeException) {
+ throw (RuntimeException) cause;
+ } else if (cause != null) {
+ throw new InvalidKeyException("No provider can be initialized with given key", cause);
+ } else if (initParams == null || initParams.key == null) {
return null;
+ } else {
+ // Since the key is not null, a suitable provider exists,
+ // and it is an InvalidKeyException.
+ throw new InvalidKeyException("No provider offers " + transformation + " for "
+ + initParams.key.getAlgorithm() + " key of class "
+ + initParams.key.getClass().getName() + " and export format "
+ + initParams.key.getFormat());
}
- for (Provider.Service service : services) {
- Engine.SpiAndProvider sap = tryTransformWithProvider(key, transformParts, type, service);
- if (sap != null) {
- return sap;
- }
- }
- return null;
}
- private static Engine.SpiAndProvider tryTransformWithProvider(Key key, String[] transformParts,
- NeedToSet type, Provider.Service service) {
+ /**
+ * Tries to initialize the {@code Cipher} from a given {@code service}. If
+ * initialization is successful, the initialized {@code spi} is returned. If
+ * the {@code service} cannot be initialized with the specified
+ * {@code initParams}, then it's expected to throw
+ * {@code InvalidKeyException} or {@code InvalidAlgorithmParameterException}
+ * as a hint to the caller that it should continue searching for a
+ * {@code Service} that will work.
+ */
+ private static Engine.SpiAndProvider tryTransformWithProvider(InitParams initParams,
+ String[] transformParts, NeedToSet type, Provider.Service service)
+ throws InvalidKeyException, InvalidAlgorithmParameterException {
try {
- if (key != null && !service.supportsParameter(key)) {
- return null;
- }
-
/*
* Check to see if the Cipher even supports the attributes before
* trying to instantiate it.
@@ -454,9 +588,6 @@ public class Cipher {
if (sap.spi == null || sap.provider == null) {
return null;
}
- if (!(sap.spi instanceof CipherSpi)) {
- return null;
- }
CipherSpi spi = (CipherSpi) sap.spi;
if (((type == NeedToSet.MODE) || (type == NeedToSet.BOTH))
&& (transformParts[1] != null)) {
@@ -466,6 +597,24 @@ public class Cipher {
&& (transformParts[2] != null)) {
spi.engineSetPadding(transformParts[2]);
}
+
+ if (initParams != null) {
+ switch (initParams.initType) {
+ case ALGORITHM_PARAMS:
+ spi.engineInit(initParams.opmode, initParams.key, initParams.params,
+ initParams.random);
+ break;
+ case ALGORITHM_PARAM_SPEC:
+ spi.engineInit(initParams.opmode, initParams.key, initParams.spec,
+ initParams.random);
+ break;
+ case KEY:
+ spi.engineInit(initParams.opmode, initParams.key, initParams.random);
+ break;
+ default:
+ throw new AssertionError("This should never be reached");
+ }
+ }
return sap;
} catch (NoSuchAlgorithmException ignored) {
} catch (NoSuchPaddingException ignored) {
@@ -577,6 +726,10 @@ public class Cipher {
}
+ /**
+ * Checks that the provided {@code mode} is one that is valid for
+ * {@code Cipher}.
+ */
private void checkMode(int mode) {
if (mode != ENCRYPT_MODE && mode != DECRYPT_MODE && mode != UNWRAP_MODE
&& mode != WRAP_MODE) {
@@ -658,7 +811,12 @@ public class Cipher {
// FIXME InvalidKeyException
// if keysize exceeds the maximum allowable keysize
// (jurisdiction policy files)
- getSpi(key).engineInit(opmode, key, random);
+ try {
+ getSpi(new InitParams(InitType.KEY, opmode, key, random, null, null));
+ } catch (InvalidAlgorithmParameterException e) {
+ // Should never happen since we only specified the key.
+ throw new ProviderException("Invalid parameters when params == null", e);
+ }
mode = opmode;
}
@@ -748,7 +906,7 @@ public class Cipher {
// FIXME InvalidAlgorithmParameterException
// cryptographic strength exceed the legal limits
// (jurisdiction policy files)
- getSpi(key).engineInit(opmode, key, params, random);
+ getSpi(new InitParams(InitType.ALGORITHM_PARAM_SPEC, opmode, key, random, params, null));
mode = opmode;
}
@@ -839,7 +997,7 @@ public class Cipher {
// FIXME InvalidAlgorithmParameterException
// cryptographic strength exceed the legal limits
// (jurisdiction policy files)
- getSpi(key).engineInit(opmode, key, params, random);
+ getSpi(new InitParams(InitType.ALGORITHM_PARAMS, opmode, key, random, null, params));
mode = opmode;
}
@@ -964,7 +1122,12 @@ public class Cipher {
// if keysize exceeds the maximum allowable keysize
// (jurisdiction policy files)
final Key key = certificate.getPublicKey();
- getSpi(key).engineInit(opmode, key, random);
+ try {
+ getSpi(new InitParams(InitType.KEY, opmode, key, random, null, null));
+ } catch (InvalidAlgorithmParameterException e) {
+ // Should never happen since we only specified the key.
+ throw new ProviderException("Invalid parameters when params == null", e);
+ }
mode = opmode;
}
@@ -1005,8 +1168,7 @@ public class Cipher {
* the offset in the input to start.
* @param inputLen
* the length of the input to transform.
- * @return the transformed bytes in a new buffer, or {@code null} if the
- * input has zero length.
+ * @return the transformed bytes in a new buffer, or {@code null} if {@code inputLen} is zero.
* @throws IllegalStateException
* if this cipher instance is not initialized for encryption or
* decryption.
@@ -1023,7 +1185,7 @@ public class Cipher {
throw new IllegalArgumentException("input == null");
}
checkInputOffsetAndCount(input.length, inputOffset, inputLen);
- if (input.length == 0) {
+ if (inputLen == 0) {
return null;
}
return getSpi().engineUpdate(input, inputOffset, inputLen);
diff --git a/luni/src/main/java/javax/crypto/ExemptionMechanism.java b/luni/src/main/java/javax/crypto/ExemptionMechanism.java
index c2d42e6..eede649 100644
--- a/luni/src/main/java/javax/crypto/ExemptionMechanism.java
+++ b/luni/src/main/java/javax/crypto/ExemptionMechanism.java
@@ -361,9 +361,6 @@ public class ExemptionMechanism {
return len;
}
- /**
- * Override to clear any key state in the instance.
- */
@Override protected void finalize() {
try {
super.finalize();
diff --git a/luni/src/main/java/javax/crypto/KeyAgreement.java b/luni/src/main/java/javax/crypto/KeyAgreement.java
index abcfd0e..22c2f3f 100644
--- a/luni/src/main/java/javax/crypto/KeyAgreement.java
+++ b/luni/src/main/java/javax/crypto/KeyAgreement.java
@@ -178,7 +178,13 @@ public class KeyAgreement {
throw new NullPointerException("algorithm == null");
}
- if (tryAlgorithm(null, provider, algorithm) == null) {
+ boolean providerSupportsAlgorithm;
+ try {
+ providerSupportsAlgorithm = tryAlgorithm(null /* key */, provider, algorithm) != null;
+ } catch (InvalidKeyException e) {
+ throw new IllegalStateException("InvalidKeyException thrown when key == null", e);
+ }
+ if (!providerSupportsAlgorithm) {
if (provider == null) {
throw new NoSuchAlgorithmException("No provider found for " + algorithm);
} else {
@@ -189,33 +195,41 @@ public class KeyAgreement {
return new KeyAgreement(null, provider, algorithm);
}
- private static Engine.SpiAndProvider tryAlgorithm(Key key, Provider provider, String algorithm) {
+ /**
+ * @throws InvalidKeyException if the specified key cannot be used to
+ * initialize any provider.
+ */
+ private static Engine.SpiAndProvider tryAlgorithm(Key key, Provider provider, String algorithm)
+ throws InvalidKeyException {
if (provider != null) {
Provider.Service service = provider.getService(SERVICE, algorithm);
if (service == null) {
return null;
}
- return tryAlgorithmWithProvider(key, service);
+ return tryAlgorithmWithProvider(service);
}
ArrayList<Provider.Service> services = ENGINE.getServices(algorithm);
- if (services == null) {
+ if (services == null || services.isEmpty()) {
return null;
}
+ boolean keySupported = false;
for (Provider.Service service : services) {
- Engine.SpiAndProvider sap = tryAlgorithmWithProvider(key, service);
- if (sap != null) {
- return sap;
+ if (key == null || service.supportsParameter(key)) {
+ keySupported = true;
+ Engine.SpiAndProvider sap = tryAlgorithmWithProvider(service);
+ if (sap != null) {
+ return sap;
+ }
}
}
+ if (!keySupported) {
+ throw new InvalidKeyException("No provider supports the provided key");
+ }
return null;
}
- private static Engine.SpiAndProvider tryAlgorithmWithProvider(Key key, Provider.Service service) {
+ private static Engine.SpiAndProvider tryAlgorithmWithProvider(Provider.Service service) {
try {
- if (key != null && !service.supportsParameter(key)) {
- return null;
- }
-
Engine.SpiAndProvider sap = ENGINE.getInstance(service, null);
if (sap.spi == null || sap.provider == null) {
return null;
@@ -231,8 +245,11 @@ public class KeyAgreement {
/**
* Makes sure a KeyAgreementSpi that matches this type is selected.
+ *
+ * @throws InvalidKeyException if the specified key cannot be used to
+ * initialize this key agreement.
*/
- private KeyAgreementSpi getSpi(Key key) {
+ private KeyAgreementSpi getSpi(Key key) throws InvalidKeyException {
synchronized (initLock) {
if (spiImpl != null && key == null) {
return spiImpl;
@@ -254,7 +271,23 @@ public class KeyAgreement {
* Convenience call when the Key is not available.
*/
private KeyAgreementSpi getSpi() {
- return getSpi(null);
+ try {
+ return getSpi(null /* key */);
+ } catch (InvalidKeyException e) {
+ throw new IllegalStateException("InvalidKeyException thrown when key == null", e);
+ }
+ }
+
+ /**
+ * Returns the {@code KeyAgreementSpi} backing this {@code KeyAgreement} or {@code null} if no
+ * {@code KeyAgreementSpi} is backing this {@code KeyAgreement}.
+ *
+ * @hide
+ */
+ public KeyAgreementSpi getCurrentSpi() {
+ synchronized (initLock) {
+ return spiImpl;
+ }
}
/**
diff --git a/luni/src/main/java/javax/crypto/Mac.java b/luni/src/main/java/javax/crypto/Mac.java
index 5a73dc5..b8fb947 100644
--- a/luni/src/main/java/javax/crypto/Mac.java
+++ b/luni/src/main/java/javax/crypto/Mac.java
@@ -182,7 +182,13 @@ public class Mac implements Cloneable {
throw new NullPointerException("algorithm == null");
}
- if (tryAlgorithm(null, provider, algorithm) == null) {
+ boolean providerSupportsAlgorithm;
+ try {
+ providerSupportsAlgorithm = tryAlgorithm(null /* key */, provider, algorithm) != null;
+ } catch (InvalidKeyException e) {
+ throw new IllegalStateException("InvalidKeyException thrown when key == null", e);
+ }
+ if (!providerSupportsAlgorithm) {
if (provider == null) {
throw new NoSuchAlgorithmException("No provider found for " + algorithm);
} else {
@@ -192,34 +198,41 @@ public class Mac implements Cloneable {
}
return new Mac(null, provider, algorithm);
}
-
- private static Engine.SpiAndProvider tryAlgorithm(Key key, Provider provider, String algorithm) {
+ /**
+ * @throws InvalidKeyException if the specified key cannot be used to
+ * initialize this mac.
+ */
+ private static Engine.SpiAndProvider tryAlgorithm(
+ Key key, Provider provider, String algorithm) throws InvalidKeyException {
if (provider != null) {
Provider.Service service = provider.getService(SERVICE, algorithm);
if (service == null) {
return null;
}
- return tryAlgorithmWithProvider(key, service);
+ return tryAlgorithmWithProvider(service);
}
ArrayList<Provider.Service> services = ENGINE.getServices(algorithm);
- if (services == null) {
+ if (services == null || services.isEmpty()) {
return null;
}
+ boolean keySupported = false;
for (Provider.Service service : services) {
- Engine.SpiAndProvider sap = tryAlgorithmWithProvider(key, service);
- if (sap != null) {
- return sap;
+ if (key == null || service.supportsParameter(key)) {
+ keySupported = true;
+ Engine.SpiAndProvider sap = tryAlgorithmWithProvider(service);
+ if (sap != null) {
+ return sap;
+ }
}
}
+ if (!keySupported) {
+ throw new InvalidKeyException("No provider supports the provided key");
+ }
return null;
}
- private static Engine.SpiAndProvider tryAlgorithmWithProvider(Key key, Provider.Service service) {
+ private static Engine.SpiAndProvider tryAlgorithmWithProvider(Provider.Service service) {
try {
- if (key != null && !service.supportsParameter(key)) {
- return null;
- }
-
Engine.SpiAndProvider sap = ENGINE.getInstance(service, null);
if (sap.spi == null || sap.provider == null) {
return null;
@@ -235,8 +248,11 @@ public class Mac implements Cloneable {
/**
* Makes sure a MacSpi that matches this type is selected.
+ *
+ * @throws InvalidKeyException if the specified key cannot be used to
+ * initialize this mac.
*/
- private MacSpi getSpi(Key key) {
+ private MacSpi getSpi(Key key) throws InvalidKeyException {
synchronized (initLock) {
if (spiImpl != null && provider != null && key == null) {
return spiImpl;
@@ -268,7 +284,23 @@ public class Mac implements Cloneable {
* Convenience call when the Key is not available.
*/
private MacSpi getSpi() {
- return getSpi(null);
+ try {
+ return getSpi(null);
+ } catch (InvalidKeyException e) {
+ throw new IllegalStateException("InvalidKeyException thrown when key == null", e);
+ }
+ }
+
+ /**
+ * Returns the {@code MacSpi} backing this {@code Mac} or {@code null} if no {@code MacSpi} is
+ * backing this {@code Mac}.
+ *
+ * @hide
+ */
+ public MacSpi getCurrentSpi() {
+ synchronized (initLock) {
+ return spiImpl;
+ }
}
/**
diff --git a/luni/src/main/java/javax/net/ssl/DefaultHostnameVerifier.java b/luni/src/main/java/javax/net/ssl/DefaultHostnameVerifier.java
deleted file mode 100644
index fd84c3e..0000000
--- a/luni/src/main/java/javax/net/ssl/DefaultHostnameVerifier.java
+++ /dev/null
@@ -1,169 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package javax.net.ssl;
-
-import java.net.InetAddress;
-import java.security.cert.Certificate;
-import java.security.cert.CertificateParsingException;
-import java.security.cert.X509Certificate;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.List;
-import java.util.Locale;
-import javax.security.auth.x500.X500Principal;
-
-/**
- * A HostnameVerifier consistent with <a
- * href="http://www.ietf.org/rfc/rfc2818.txt">RFC 2818</a>.
- *
- * @hide accessible via HttpsURLConnection.getDefaultHostnameVerifier()
- */
-public final class DefaultHostnameVerifier implements HostnameVerifier {
- private static final int ALT_DNS_NAME = 2;
- private static final int ALT_IPA_NAME = 7;
-
- public final boolean verify(String host, SSLSession session) {
- try {
- Certificate[] certificates = session.getPeerCertificates();
- return verify(host, (X509Certificate) certificates[0]);
- } catch (SSLException e) {
- return false;
- }
- }
-
- public boolean verify(String host, X509Certificate certificate) {
- return InetAddress.isNumeric(host)
- ? verifyIpAddress(host, certificate)
- : verifyHostName(host, certificate);
- }
-
- /**
- * Returns true if {@code certificate} matches {@code ipAddress}.
- */
- private boolean verifyIpAddress(String ipAddress, X509Certificate certificate) {
- for (String altName : getSubjectAltNames(certificate, ALT_IPA_NAME)) {
- if (ipAddress.equalsIgnoreCase(altName)) {
- return true;
- }
- }
- return false;
- }
-
- /**
- * Returns true if {@code certificate} matches {@code hostName}.
- */
- private boolean verifyHostName(String hostName, X509Certificate certificate) {
- hostName = hostName.toLowerCase(Locale.US);
- boolean hasDns = false;
- for (String altName : getSubjectAltNames(certificate, ALT_DNS_NAME)) {
- hasDns = true;
- if (verifyHostName(hostName, altName)) {
- return true;
- }
- }
-
- if (!hasDns) {
- X500Principal principal = certificate.getSubjectX500Principal();
- // RFC 2818 advises using the most specific name for matching.
- String cn = new DistinguishedNameParser(principal).findMostSpecific("cn");
- if (cn != null) {
- return verifyHostName(hostName, cn);
- }
- }
-
- return false;
- }
-
- private List<String> getSubjectAltNames(X509Certificate certificate, int type) {
- List<String> result = new ArrayList<String>();
- try {
- Collection<?> subjectAltNames = certificate.getSubjectAlternativeNames();
- if (subjectAltNames == null) {
- return Collections.emptyList();
- }
- for (Object subjectAltName : subjectAltNames) {
- List<?> entry = (List<?>) subjectAltName;
- if (entry == null || entry.size() < 2) {
- continue;
- }
- Integer altNameType = (Integer) entry.get(0);
- if (altNameType == null) {
- continue;
- }
- if (altNameType == type) {
- String altName = (String) entry.get(1);
- if (altName != null) {
- result.add(altName);
- }
- }
- }
- return result;
- } catch (CertificateParsingException e) {
- return Collections.emptyList();
- }
- }
-
- /**
- * Returns true if {@code hostName} matches the name or pattern {@code cn}.
- *
- * @param hostName lowercase host name.
- * @param cn certificate host name. May include wildcards like
- * {@code *.android.com}.
- */
- public boolean verifyHostName(String hostName, String cn) {
- if (hostName == null || hostName.isEmpty() || cn == null || cn.isEmpty()) {
- return false;
- }
-
- cn = cn.toLowerCase(Locale.US);
-
- if (!cn.contains("*")) {
- return hostName.equals(cn);
- }
-
- if (cn.startsWith("*.") && hostName.equals(cn.substring(2))) {
- return true; // "*.foo.com" matches "foo.com"
- }
-
- int asterisk = cn.indexOf('*');
- int dot = cn.indexOf('.');
- if (asterisk > dot) {
- return false; // malformed; wildcard must be in the first part of the cn
- }
-
- if (!hostName.regionMatches(0, cn, 0, asterisk)) {
- return false; // prefix before '*' doesn't match
- }
-
- int suffixLength = cn.length() - (asterisk + 1);
- int suffixStart = hostName.length() - suffixLength;
- if (hostName.indexOf('.', asterisk) < suffixStart) {
- // TODO: remove workaround for *.clients.google.com http://b/5426333
- if (!hostName.endsWith(".clients.google.com")) {
- return false; // wildcard '*' can't match a '.'
- }
- }
-
- if (!hostName.regionMatches(suffixStart, cn, asterisk + 1, suffixLength)) {
- return false; // suffix after '*' doesn't match
- }
-
- return true;
- }
-}
diff --git a/luni/src/main/java/javax/net/ssl/HttpsURLConnection.java b/luni/src/main/java/javax/net/ssl/HttpsURLConnection.java
index ab86a9b..1bd48fd 100644
--- a/luni/src/main/java/javax/net/ssl/HttpsURLConnection.java
+++ b/luni/src/main/java/javax/net/ssl/HttpsURLConnection.java
@@ -109,7 +109,16 @@ public abstract class HttpsURLConnection extends HttpURLConnection {
* it.
*/
private static class NoPreloadHolder {
- public static HostnameVerifier defaultHostnameVerifier = new DefaultHostnameVerifier();
+ public static HostnameVerifier defaultHostnameVerifier;
+ static {
+ try {
+ defaultHostnameVerifier = (HostnameVerifier)
+ Class.forName("com.android.okhttp.internal.tls.OkHostnameVerifier")
+ .getField("INSTANCE").get(null);
+ } catch (Exception e) {
+ throw new AssertionError("Failed to obtain okhttp HostnameVerifier", e);
+ }
+ }
public static SSLSocketFactory defaultSSLSocketFactory = (SSLSocketFactory) SSLSocketFactory
.getDefault();
diff --git a/luni/src/main/java/javax/net/ssl/SSLEngine.java b/luni/src/main/java/javax/net/ssl/SSLEngine.java
index cbf02ac..e8d1a51 100644
--- a/luni/src/main/java/javax/net/ssl/SSLEngine.java
+++ b/luni/src/main/java/javax/net/ssl/SSLEngine.java
@@ -28,6 +28,14 @@ import java.nio.ByteBuffer;
* <p>{@code SSLEngine} instances obtained from default {@link SSLContext} are configured as
* follows:
*
+ * <style type="text/css">
+ * tr.deprecated {
+ * background-color: #ccc;
+ * color: #999;
+ * font-style: italic;
+ * }
+ * </style>
+ *
* <h4>Protocols</h4>
* <table>
* <thead>
@@ -71,155 +79,155 @@ import java.nio.ByteBuffer;
* </tr>
* </thead>
* <tbody>
- * <tr>
+ * <tr class="deprecated">
* <td>SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA</td>
- * <td>9+</td>
- * <td>9-19</td>
+ * <td>9&ndash;22</td>
+ * <td>9&ndash;19</td>
* </tr>
- * <tr>
+ * <tr class="deprecated">
* <td>SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA</td>
- * <td>9+</td>
- * <td>9-19</td>
+ * <td>9&ndash;22</td>
+ * <td>9&ndash;19</td>
* </tr>
- * <tr>
+ * <tr class="deprecated">
* <td>SSL_DHE_DSS_WITH_DES_CBC_SHA</td>
- * <td>9+</td>
- * <td>9-19</td>
+ * <td>9&ndash;22</td>
+ * <td>9&ndash;19</td>
* </tr>
- * <tr>
+ * <tr class="deprecated">
* <td>SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA</td>
- * <td>9+</td>
- * <td>9-19</td>
+ * <td>9&ndash;22</td>
+ * <td>9&ndash;19</td>
* </tr>
- * <tr>
+ * <tr class="deprecated">
* <td>SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA</td>
- * <td>9+</td>
- * <td>9-19</td>
+ * <td>9&ndash;22</td>
+ * <td>9&ndash;19</td>
* </tr>
- * <tr>
+ * <tr class="deprecated">
* <td>SSL_DHE_RSA_WITH_DES_CBC_SHA</td>
- * <td>9+</td>
- * <td>9-19</td>
+ * <td>9&ndash;22</td>
+ * <td>9&ndash;19</td>
* </tr>
- * <tr>
+ * <tr class="deprecated">
* <td>SSL_DH_anon_EXPORT_WITH_DES40_CBC_SHA</td>
- * <td>9+</td>
+ * <td>9&ndash;22</td>
* <td></td>
* </tr>
- * <tr>
+ * <tr class="deprecated">
* <td>SSL_DH_anon_EXPORT_WITH_RC4_40_MD5</td>
- * <td>9+</td>
+ * <td>9&ndash;22</td>
* <td></td>
* </tr>
- * <tr>
+ * <tr class="deprecated">
* <td>SSL_DH_anon_WITH_3DES_EDE_CBC_SHA</td>
- * <td>9+</td>
+ * <td>9&ndash;22</td>
* <td></td>
* </tr>
- * <tr>
+ * <tr class="deprecated">
* <td>SSL_DH_anon_WITH_DES_CBC_SHA</td>
- * <td>9+</td>
+ * <td>9&ndash;22</td>
* <td></td>
* </tr>
- * <tr>
+ * <tr class="deprecated">
* <td>SSL_DH_anon_WITH_RC4_128_MD5</td>
- * <td>9+</td>
+ * <td>9&ndash;22</td>
* <td></td>
* </tr>
- * <tr>
+ * <tr class="deprecated">
* <td>SSL_RSA_EXPORT_WITH_DES40_CBC_SHA</td>
- * <td>9+</td>
- * <td>9-19</td>
+ * <td>9&ndash;22</td>
+ * <td>9&ndash;19</td>
* </tr>
- * <tr>
+ * <tr class="deprecated">
* <td>SSL_RSA_EXPORT_WITH_RC4_40_MD5</td>
- * <td>9+</td>
- * <td>9-19</td>
+ * <td>9&ndash;22</td>
+ * <td>9&ndash;19</td>
* </tr>
* <tr>
* <td>SSL_RSA_WITH_3DES_EDE_CBC_SHA</td>
* <td>9+</td>
- * <td>9-19</td>
+ * <td>9&ndash;19</td>
* </tr>
- * <tr>
+ * <tr class="deprecated">
* <td>SSL_RSA_WITH_DES_CBC_SHA</td>
- * <td>9+</td>
- * <td>9-19</td>
+ * <td>9&ndash;22</td>
+ * <td>9&ndash;19</td>
* </tr>
- * <tr>
+ * <tr class="deprecated">
* <td>SSL_RSA_WITH_NULL_MD5</td>
- * <td>9+</td>
+ * <td>9&ndash;22</td>
* <td></td>
* </tr>
- * <tr>
+ * <tr class="deprecated">
* <td>SSL_RSA_WITH_NULL_SHA</td>
- * <td>9+</td>
+ * <td>9&ndash;22</td>
* <td></td>
* </tr>
* <tr>
* <td>SSL_RSA_WITH_RC4_128_MD5</td>
* <td>9+</td>
- * <td>9-19</td>
+ * <td>9&ndash;19</td>
* </tr>
* <tr>
* <td>SSL_RSA_WITH_RC4_128_SHA</td>
* <td>9+</td>
* <td>9+</td>
* </tr>
- * <tr>
+ * <tr class="deprecated">
* <td>TLS_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA</td>
- * <td>1-8</td>
- * <td>1-8</td>
+ * <td>1&ndash;8</td>
+ * <td>1&ndash;8</td>
* </tr>
- * <tr>
+ * <tr class="deprecated">
* <td>TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA</td>
- * <td>1-8</td>
- * <td>1-8</td>
+ * <td>1&ndash;8</td>
+ * <td>1&ndash;8</td>
* </tr>
- * <tr>
+ * <tr class="deprecated">
* <td>TLS_DHE_DSS_WITH_AES_128_CBC_SHA</td>
- * <td>9+</td>
- * <td>9+</td>
+ * <td>9&ndash;22</td>
+ * <td>9&ndash;22</td>
* </tr>
- * <tr>
+ * <tr class="deprecated">
* <td>TLS_DHE_DSS_WITH_AES_128_CBC_SHA256</td>
- * <td>20+</td>
+ * <td>20&ndash;22</td>
* <td></td>
* </tr>
- * <tr>
+ * <tr class="deprecated">
* <td>TLS_DHE_DSS_WITH_AES_128_GCM_SHA256</td>
- * <td>20+</td>
+ * <td>20&ndash;22</td>
* <td></td>
* </tr>
- * <tr>
+ * <tr class="deprecated">
* <td>TLS_DHE_DSS_WITH_AES_256_CBC_SHA</td>
- * <td>9+</td>
- * <td>20+</td>
+ * <td>9&ndash;22</td>
+ * <td>20&ndash;22</td>
* </tr>
- * <tr>
+ * <tr class="deprecated">
* <td>TLS_DHE_DSS_WITH_AES_256_CBC_SHA256</td>
- * <td>20+</td>
+ * <td>20&ndash;22</td>
* <td></td>
* </tr>
- * <tr>
+ * <tr class="deprecated">
* <td>TLS_DHE_DSS_WITH_AES_256_GCM_SHA384</td>
- * <td>20+</td>
+ * <td>20&ndash;22</td>
* <td></td>
* </tr>
- * <tr>
+ * <tr class="deprecated">
* <td>TLS_DHE_DSS_WITH_DES_CBC_SHA</td>
- * <td>1-8</td>
- * <td>1-8</td>
+ * <td>1&ndash;8</td>
+ * <td>1&ndash;8</td>
* </tr>
- * <tr>
+ * <tr class="deprecated">
* <td>TLS_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA</td>
- * <td>1-8</td>
- * <td>1-8</td>
+ * <td>1&ndash;8</td>
+ * <td>1&ndash;8</td>
* </tr>
- * <tr>
+ * <tr class="deprecated">
* <td>TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA</td>
- * <td>1-8</td>
- * <td>1-8</td>
+ * <td>1&ndash;8</td>
+ * <td>1&ndash;8</td>
* </tr>
* <tr>
* <td>TLS_DHE_RSA_WITH_AES_128_CBC_SHA</td>
@@ -251,89 +259,89 @@ import java.nio.ByteBuffer;
* <td>20+</td>
* <td>20+</td>
* </tr>
- * <tr>
+ * <tr class="deprecated">
* <td>TLS_DHE_RSA_WITH_DES_CBC_SHA</td>
- * <td>1-8</td>
- * <td>1-8</td>
+ * <td>1&ndash;8</td>
+ * <td>1&ndash;8</td>
* </tr>
- * <tr>
+ * <tr class="deprecated">
* <td>TLS_DH_DSS_EXPORT_WITH_DES40_CBC_SHA</td>
- * <td>1-8</td>
+ * <td>1&ndash;8</td>
* <td></td>
* </tr>
- * <tr>
+ * <tr class="deprecated">
* <td>TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA</td>
- * <td>1-8</td>
+ * <td>1&ndash;8</td>
* <td></td>
* </tr>
- * <tr>
+ * <tr class="deprecated">
* <td>TLS_DH_DSS_WITH_DES_CBC_SHA</td>
- * <td>1-8</td>
+ * <td>1&ndash;8</td>
* <td></td>
* </tr>
- * <tr>
+ * <tr class="deprecated">
* <td>TLS_DH_RSA_EXPORT_WITH_DES40_CBC_SHA</td>
- * <td>1-8</td>
+ * <td>1&ndash;8</td>
* <td></td>
* </tr>
- * <tr>
+ * <tr class="deprecated">
* <td>TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA</td>
- * <td>1-8</td>
+ * <td>1&ndash;8</td>
* <td></td>
* </tr>
- * <tr>
+ * <tr class="deprecated">
* <td>TLS_DH_RSA_WITH_DES_CBC_SHA</td>
- * <td>1-8</td>
+ * <td>1&ndash;8</td>
* <td></td>
* </tr>
- * <tr>
+ * <tr class="deprecated">
* <td>TLS_DH_anon_EXPORT_WITH_DES40_CBC_SHA</td>
- * <td>1-8</td>
+ * <td>1&ndash;8</td>
* <td></td>
* </tr>
- * <tr>
+ * <tr class="deprecated">
* <td>TLS_DH_anon_WITH_3DES_EDE_CBC_SHA</td>
- * <td>1-8</td>
+ * <td>1&ndash;8</td>
* <td></td>
* </tr>
- * <tr>
+ * <tr class="deprecated">
* <td>TLS_DH_anon_WITH_AES_128_CBC_SHA</td>
- * <td>9+</td>
+ * <td>9&ndash;22</td>
* <td></td>
* </tr>
- * <tr>
+ * <tr class="deprecated">
* <td>TLS_DH_anon_WITH_AES_128_CBC_SHA256</td>
- * <td>20+</td>
+ * <td>20&ndash;22</td>
* <td></td>
* </tr>
- * <tr>
+ * <tr class="deprecated">
* <td>TLS_DH_anon_WITH_AES_128_GCM_SHA256</td>
- * <td>20+</td>
+ * <td>20&ndash;22</td>
* <td></td>
* </tr>
- * <tr>
+ * <tr class="deprecated">
* <td>TLS_DH_anon_WITH_AES_256_CBC_SHA</td>
- * <td>9+</td>
+ * <td>9&ndash;22</td>
* <td></td>
* </tr>
- * <tr>
+ * <tr class="deprecated">
* <td>TLS_DH_anon_WITH_AES_256_CBC_SHA256</td>
- * <td>20+</td>
+ * <td>20&ndash;22</td>
* <td></td>
* </tr>
- * <tr>
+ * <tr class="deprecated">
* <td>TLS_DH_anon_WITH_AES_256_GCM_SHA384</td>
- * <td>20+</td>
+ * <td>20&ndash;22</td>
* <td></td>
* </tr>
- * <tr>
+ * <tr class="deprecated">
* <td>TLS_DH_anon_WITH_DES_CBC_SHA</td>
- * <td>1-8</td>
+ * <td>1&ndash;8</td>
* <td></td>
* </tr>
- * <tr>
+ * <tr class="deprecated">
* <td>TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA</td>
- * <td>20+</td>
+ * <td>20&ndash;22</td>
* <td></td>
* </tr>
* <tr>
@@ -366,9 +374,9 @@ import java.nio.ByteBuffer;
* <td>20+</td>
* <td>20+</td>
* </tr>
- * <tr>
+ * <tr class="deprecated">
* <td>TLS_ECDHE_ECDSA_WITH_NULL_SHA</td>
- * <td>20+</td>
+ * <td>20&ndash;22</td>
* <td></td>
* </tr>
* <tr>
@@ -376,9 +384,9 @@ import java.nio.ByteBuffer;
* <td>20+</td>
* <td>20+</td>
* </tr>
- * <tr>
+ * <tr class="deprecated">
* <td>TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA</td>
- * <td>20+</td>
+ * <td>20&ndash;22</td>
* <td></td>
* </tr>
* <tr>
@@ -411,9 +419,9 @@ import java.nio.ByteBuffer;
* <td>20+</td>
* <td>20+</td>
* </tr>
- * <tr>
+ * <tr class="deprecated">
* <td>TLS_ECDHE_RSA_WITH_NULL_SHA</td>
- * <td>20+</td>
+ * <td>20&ndash;22</td>
* <td></td>
* </tr>
* <tr>
@@ -421,119 +429,119 @@ import java.nio.ByteBuffer;
* <td>20+</td>
* <td>20+</td>
* </tr>
- * <tr>
+ * <tr class="deprecated">
* <td>TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA</td>
- * <td>20+</td>
+ * <td>20&ndash;22</td>
* <td></td>
* </tr>
- * <tr>
+ * <tr class="deprecated">
* <td>TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA</td>
- * <td>20+</td>
+ * <td>20&ndash;22</td>
* <td></td>
* </tr>
- * <tr>
+ * <tr class="deprecated">
* <td>TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256</td>
- * <td>20+</td>
+ * <td>20&ndash;22</td>
* <td></td>
* </tr>
- * <tr>
+ * <tr class="deprecated">
* <td>TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256</td>
- * <td>20+</td>
+ * <td>20&ndash;22</td>
* <td></td>
* </tr>
- * <tr>
+ * <tr class="deprecated">
* <td>TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA</td>
- * <td>20+</td>
+ * <td>20&ndash;22</td>
* <td></td>
* </tr>
- * <tr>
+ * <tr class="deprecated">
* <td>TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384</td>
- * <td>20+</td>
+ * <td>20&ndash;22</td>
* <td></td>
* </tr>
- * <tr>
+ * <tr class="deprecated">
* <td>TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384</td>
- * <td>20+</td>
+ * <td>20&ndash;22</td>
* <td></td>
* </tr>
- * <tr>
+ * <tr class="deprecated">
* <td>TLS_ECDH_ECDSA_WITH_NULL_SHA</td>
- * <td>20+</td>
+ * <td>20&ndash;22</td>
* <td></td>
* </tr>
- * <tr>
+ * <tr class="deprecated">
* <td>TLS_ECDH_ECDSA_WITH_RC4_128_SHA</td>
- * <td>20+</td>
+ * <td>20&ndash;22</td>
* <td></td>
* </tr>
- * <tr>
+ * <tr class="deprecated">
* <td>TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA</td>
- * <td>20+</td>
+ * <td>20&ndash;22</td>
* <td></td>
* </tr>
- * <tr>
+ * <tr class="deprecated">
* <td>TLS_ECDH_RSA_WITH_AES_128_CBC_SHA</td>
- * <td>20+</td>
+ * <td>20&ndash;22</td>
* <td></td>
* </tr>
- * <tr>
+ * <tr class="deprecated">
* <td>TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256</td>
- * <td>20+</td>
+ * <td>20&ndash;22</td>
* <td></td>
* </tr>
- * <tr>
+ * <tr class="deprecated">
* <td>TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256</td>
- * <td>20+</td>
+ * <td>20&ndash;22</td>
* <td></td>
* </tr>
- * <tr>
+ * <tr class="deprecated">
* <td>TLS_ECDH_RSA_WITH_AES_256_CBC_SHA</td>
- * <td>20+</td>
+ * <td>20&ndash;22</td>
* <td></td>
* </tr>
- * <tr>
+ * <tr class="deprecated">
* <td>TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384</td>
- * <td>20+</td>
+ * <td>20&ndash;22</td>
* <td></td>
* </tr>
- * <tr>
+ * <tr class="deprecated">
* <td>TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384</td>
- * <td>20+</td>
+ * <td>20&ndash;22</td>
* <td></td>
* </tr>
- * <tr>
+ * <tr class="deprecated">
* <td>TLS_ECDH_RSA_WITH_NULL_SHA</td>
- * <td>20+</td>
+ * <td>20&ndash;22</td>
* <td></td>
* </tr>
- * <tr>
+ * <tr class="deprecated">
* <td>TLS_ECDH_RSA_WITH_RC4_128_SHA</td>
- * <td>20+</td>
+ * <td>20&ndash;22</td>
* <td></td>
* </tr>
- * <tr>
+ * <tr class="deprecated">
* <td>TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA</td>
- * <td>20+</td>
+ * <td>20&ndash;22</td>
* <td></td>
* </tr>
- * <tr>
+ * <tr class="deprecated">
* <td>TLS_ECDH_anon_WITH_AES_128_CBC_SHA</td>
- * <td>20+</td>
+ * <td>20&ndash;22</td>
* <td></td>
* </tr>
- * <tr>
+ * <tr class="deprecated">
* <td>TLS_ECDH_anon_WITH_AES_256_CBC_SHA</td>
- * <td>20+</td>
+ * <td>20&ndash;22</td>
* <td></td>
* </tr>
- * <tr>
+ * <tr class="deprecated">
* <td>TLS_ECDH_anon_WITH_NULL_SHA</td>
- * <td>20+</td>
+ * <td>20&ndash;22</td>
* <td></td>
* </tr>
- * <tr>
+ * <tr class="deprecated">
* <td>TLS_ECDH_anon_WITH_RC4_128_SHA</td>
- * <td>20+</td>
+ * <td>20&ndash;22</td>
* <td></td>
* </tr>
* <tr>
@@ -556,14 +564,14 @@ import java.nio.ByteBuffer;
* <td>21+</td>
* <td>21+</td>
* </tr>
- * <tr>
+ * <tr class="deprecated">
* <td>TLS_NULL_WITH_NULL_NULL</td>
- * <td>1-8</td>
+ * <td>1&ndash;8</td>
* <td></td>
* </tr>
- * <tr>
+ * <tr class="deprecated">
* <td>TLS_PSK_WITH_3DES_EDE_CBC_SHA</td>
- * <td>21+</td>
+ * <td>21&ndash;22</td>
* <td></td>
* </tr>
* <tr>
@@ -581,15 +589,15 @@ import java.nio.ByteBuffer;
* <td>21+</td>
* <td></td>
* </tr>
- * <tr>
+ * <tr class="deprecated">
* <td>TLS_RSA_EXPORT_WITH_DES40_CBC_SHA</td>
- * <td>1-8</td>
- * <td>1-8</td>
+ * <td>1&ndash;8</td>
+ * <td>1&ndash;8</td>
* </tr>
- * <tr>
+ * <tr class="deprecated">
* <td>TLS_RSA_WITH_3DES_EDE_CBC_SHA</td>
- * <td>1-8</td>
- * <td>1-8</td>
+ * <td>1&ndash;8</td>
+ * <td>1&ndash;8</td>
* </tr>
* <tr>
* <td>TLS_RSA_WITH_AES_128_CBC_SHA</td>
@@ -621,24 +629,24 @@ import java.nio.ByteBuffer;
* <td>20+</td>
* <td>20+</td>
* </tr>
- * <tr>
+ * <tr class="deprecated">
* <td>TLS_RSA_WITH_DES_CBC_SHA</td>
- * <td>1-8</td>
- * <td>1-8</td>
+ * <td>1&ndash;8</td>
+ * <td>1&ndash;8</td>
* </tr>
- * <tr>
+ * <tr class="deprecated">
* <td>TLS_RSA_WITH_NULL_MD5</td>
- * <td>1-8</td>
+ * <td>1&ndash;8</td>
* <td></td>
* </tr>
- * <tr>
+ * <tr class="deprecated">
* <td>TLS_RSA_WITH_NULL_SHA</td>
- * <td>1-8</td>
+ * <td>1&ndash;8</td>
* <td></td>
* </tr>
- * <tr>
+ * <tr class="deprecated">
* <td>TLS_RSA_WITH_NULL_SHA256</td>
- * <td>20+</td>
+ * <td>20&ndash;22</td>
* <td></td>
* </tr>
* </tbody>
diff --git a/luni/src/main/java/javax/net/ssl/SSLSocket.java b/luni/src/main/java/javax/net/ssl/SSLSocket.java
index dc406e1..f48870e 100644
--- a/luni/src/main/java/javax/net/ssl/SSLSocket.java
+++ b/luni/src/main/java/javax/net/ssl/SSLSocket.java
@@ -30,6 +30,14 @@ import java.net.UnknownHostException;
* <p>{@code SSLSocket} instances obtained from default {@link SSLSocketFactory},
* {@link SSLServerSocketFactory}, and {@link SSLContext} are configured as follows:
*
+ * <style type="text/css">
+ * tr.deprecated {
+ * background-color: #ccc;
+ * color: #999;
+ * font-style: italic;
+ * }
+ * </style>
+ *
* <h4>Protocols</h4>
*
* <p>Client socket:
@@ -115,129 +123,129 @@ import java.net.UnknownHostException;
* </tr>
* </thead>
* <tbody>
- * <tr>
+ * <tr class="deprecated">
* <td>SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA</td>
- * <td>9+</td>
- * <td>9-19</td>
+ * <td>9&ndash;22</td>
+ * <td>9&ndash;19</td>
* </tr>
- * <tr>
+ * <tr class="deprecated">
* <td>SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA</td>
- * <td>9+</td>
- * <td>9-19</td>
+ * <td>9&ndash;22</td>
+ * <td>9&ndash;19</td>
* </tr>
- * <tr>
+ * <tr class="deprecated">
* <td>SSL_DHE_DSS_WITH_DES_CBC_SHA</td>
- * <td>9+</td>
- * <td>9-19</td>
+ * <td>9&ndash;22</td>
+ * <td>9&ndash;19</td>
* </tr>
- * <tr>
+ * <tr class="deprecated">
* <td>SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA</td>
- * <td>9+</td>
- * <td>9-19</td>
+ * <td>9&ndash;22</td>
+ * <td>9&ndash;19</td>
* </tr>
- * <tr>
+ * <tr class="deprecated">
* <td>SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA</td>
- * <td>9+</td>
- * <td>9-19</td>
+ * <td>9&ndash;22</td>
+ * <td>9&ndash;19</td>
* </tr>
- * <tr>
+ * <tr class="deprecated">
* <td>SSL_DHE_RSA_WITH_DES_CBC_SHA</td>
- * <td>9+</td>
- * <td>9-19</td>
+ * <td>9&ndash;22</td>
+ * <td>9&ndash;19</td>
* </tr>
- * <tr>
+ * <tr class="deprecated">
* <td>SSL_DH_anon_EXPORT_WITH_DES40_CBC_SHA</td>
- * <td>9+</td>
+ * <td>9&ndash;22</td>
* <td></td>
* </tr>
- * <tr>
+ * <tr class="deprecated">
* <td>SSL_DH_anon_EXPORT_WITH_RC4_40_MD5</td>
- * <td>9+</td>
+ * <td>9&ndash;22</td>
* <td></td>
* </tr>
- * <tr>
+ * <tr class="deprecated">
* <td>SSL_DH_anon_WITH_3DES_EDE_CBC_SHA</td>
- * <td>9+</td>
+ * <td>9&ndash;22</td>
* <td></td>
* </tr>
- * <tr>
+ * <tr class="deprecated">
* <td>SSL_DH_anon_WITH_DES_CBC_SHA</td>
- * <td>9+</td>
+ * <td>9&ndash;22</td>
* <td></td>
* </tr>
- * <tr>
+ * <tr class="deprecated">
* <td>SSL_DH_anon_WITH_RC4_128_MD5</td>
- * <td>9+</td>
+ * <td>9&ndash;22</td>
* <td></td>
* </tr>
- * <tr>
+ * <tr class="deprecated">
* <td>SSL_RSA_EXPORT_WITH_DES40_CBC_SHA</td>
- * <td>9+</td>
- * <td>9-19</td>
+ * <td>9&ndash;22</td>
+ * <td>9&ndash;19</td>
* </tr>
- * <tr>
+ * <tr class="deprecated">
* <td>SSL_RSA_EXPORT_WITH_RC4_40_MD5</td>
- * <td>9+</td>
- * <td>9-19</td>
+ * <td>9&ndash;22</td>
+ * <td>9&ndash;19</td>
* </tr>
* <tr>
* <td>SSL_RSA_WITH_3DES_EDE_CBC_SHA</td>
* <td>9+</td>
- * <td>9-19</td>
+ * <td>9&ndash;19</td>
* </tr>
- * <tr>
+ * <tr class="deprecated">
* <td>SSL_RSA_WITH_DES_CBC_SHA</td>
- * <td>9+</td>
- * <td>9-19</td>
+ * <td>9&ndash;22</td>
+ * <td>9&ndash;19</td>
* </tr>
- * <tr>
+ * <tr class="deprecated">
* <td>SSL_RSA_WITH_NULL_MD5</td>
- * <td>9+</td>
+ * <td>9&ndash;22</td>
* <td></td>
* </tr>
- * <tr>
+ * <tr class="deprecated">
* <td>SSL_RSA_WITH_NULL_SHA</td>
- * <td>9+</td>
+ * <td>9&ndash;22</td>
* <td></td>
* </tr>
* <tr>
* <td>SSL_RSA_WITH_RC4_128_MD5</td>
* <td>9+</td>
- * <td>9-19</td>
+ * <td>9&ndash;19</td>
* </tr>
* <tr>
* <td>SSL_RSA_WITH_RC4_128_SHA</td>
* <td>9+</td>
* <td>9+</td>
* </tr>
- * <tr>
+ * <tr class="deprecated">
* <td>TLS_DHE_DSS_WITH_AES_128_CBC_SHA</td>
- * <td>9+</td>
- * <td>9+</td>
+ * <td>9&ndash;22</td>
+ * <td>9&ndash;22</td>
* </tr>
- * <tr>
+ * <tr class="deprecated">
* <td>TLS_DHE_DSS_WITH_AES_128_CBC_SHA256</td>
- * <td>20+</td>
+ * <td>20&ndash;22</td>
* <td></td>
* </tr>
- * <tr>
+ * <tr class="deprecated">
* <td>TLS_DHE_DSS_WITH_AES_128_GCM_SHA256</td>
- * <td>20+</td>
+ * <td>20&ndash;22</td>
* <td></td>
* </tr>
- * <tr>
+ * <tr class="deprecated">
* <td>TLS_DHE_DSS_WITH_AES_256_CBC_SHA</td>
- * <td>9+</td>
- * <td>11+</td>
+ * <td>9&ndash;22</td>
+ * <td>11&ndash;22</td>
* </tr>
- * <tr>
+ * <tr class="deprecated">
* <td>TLS_DHE_DSS_WITH_AES_256_CBC_SHA256</td>
- * <td>20+</td>
+ * <td>20&ndash;22</td>
* <td></td>
* </tr>
- * <tr>
+ * <tr class="deprecated">
* <td>TLS_DHE_DSS_WITH_AES_256_GCM_SHA384</td>
- * <td>20+</td>
+ * <td>20&ndash;22</td>
* <td></td>
* </tr>
* <tr>
@@ -270,40 +278,40 @@ import java.net.UnknownHostException;
* <td>20+</td>
* <td>20+</td>
* </tr>
- * <tr>
+ * <tr class="deprecated">
* <td>TLS_DH_anon_WITH_AES_128_CBC_SHA</td>
- * <td>9+</td>
+ * <td>9&ndash;22</td>
* <td></td>
* </tr>
- * <tr>
+ * <tr class="deprecated">
* <td>TLS_DH_anon_WITH_AES_128_CBC_SHA256</td>
- * <td>20+</td>
+ * <td>20&ndash;22</td>
* <td></td>
* </tr>
- * <tr>
+ * <tr class="deprecated">
* <td>TLS_DH_anon_WITH_AES_128_GCM_SHA256</td>
- * <td>20+</td>
+ * <td>20&ndash;22</td>
* <td></td>
* </tr>
- * <tr>
+ * <tr class="deprecated">
* <td>TLS_DH_anon_WITH_AES_256_CBC_SHA</td>
- * <td>9+</td>
+ * <td>9&ndash;22</td>
* <td></td>
* </tr>
- * <tr>
+ * <tr class="deprecated">
* <td>TLS_DH_anon_WITH_AES_256_CBC_SHA256</td>
- * <td>20+</td>
+ * <td>20&ndash;22</td>
* <td></td>
* </tr>
- * <tr>
+ * <tr class="deprecated">
* <td>TLS_DH_anon_WITH_AES_256_GCM_SHA384</td>
- * <td>20+</td>
+ * <td>20&ndash;22</td>
* <td></td>
* </tr>
- * <tr>
+ * <tr class="deprecated">
* <td>TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA</td>
- * <td>11+</td>
- * <td>11-19</td>
+ * <td>11&ndash;22</td>
+ * <td>11&ndash;19</td>
* </tr>
* <tr>
* <td>TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA</td>
@@ -335,9 +343,9 @@ import java.net.UnknownHostException;
* <td>20+</td>
* <td>20+</td>
* </tr>
- * <tr>
+ * <tr class="deprecated">
* <td>TLS_ECDHE_ECDSA_WITH_NULL_SHA</td>
- * <td>11+</td>
+ * <td>11&ndash;22</td>
* <td></td>
* </tr>
* <tr>
@@ -355,10 +363,10 @@ import java.net.UnknownHostException;
* <td>21+</td>
* <td>21+</td>
* </tr>
- * <tr>
+ * <tr class="deprecated">
* <td>TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA</td>
- * <td>11+</td>
- * <td>11-19</td>
+ * <td>11&ndash;22</td>
+ * <td>11&ndash;19</td>
* </tr>
* <tr>
* <td>TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA</td>
@@ -390,9 +398,9 @@ import java.net.UnknownHostException;
* <td>20+</td>
* <td>20+</td>
* </tr>
- * <tr>
+ * <tr class="deprecated">
* <td>TLS_ECDHE_RSA_WITH_NULL_SHA</td>
- * <td>11+</td>
+ * <td>11&ndash;22</td>
* <td></td>
* </tr>
* <tr>
@@ -400,119 +408,119 @@ import java.net.UnknownHostException;
* <td>11+</td>
* <td>11+</td>
* </tr>
- * <tr>
+ * <tr class="deprecated">
* <td>TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA</td>
- * <td>11+</td>
- * <td>11-19</td>
+ * <td>11&ndash;22</td>
+ * <td>11&ndash;19</td>
* </tr>
- * <tr>
+ * <tr class="deprecated">
* <td>TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA</td>
- * <td>11+</td>
- * <td>11-19</td>
+ * <td>11&ndash;22</td>
+ * <td>11&ndash;19</td>
* </tr>
- * <tr>
+ * <tr class="deprecated">
* <td>TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256</td>
- * <td>20+</td>
+ * <td>20&ndash;22</td>
* <td></td>
* </tr>
- * <tr>
+ * <tr class="deprecated">
* <td>TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256</td>
- * <td>20+</td>
+ * <td>20&ndash;22</td>
* <td></td>
* </tr>
- * <tr>
+ * <tr class="deprecated">
* <td>TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA</td>
- * <td>11+</td>
- * <td>11-19</td>
+ * <td>11&ndash;22</td>
+ * <td>11&ndash;19</td>
* </tr>
- * <tr>
+ * <tr class="deprecated">
* <td>TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384</td>
- * <td>20+</td>
+ * <td>20&ndash;22</td>
* <td></td>
* </tr>
- * <tr>
+ * <tr class="deprecated">
* <td>TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384</td>
- * <td>20+</td>
+ * <td>20&ndash;22</td>
* <td></td>
* </tr>
- * <tr>
+ * <tr class="deprecated">
* <td>TLS_ECDH_ECDSA_WITH_NULL_SHA</td>
- * <td>11+</td>
+ * <td>11&ndash;22</td>
* <td></td>
* </tr>
- * <tr>
+ * <tr class="deprecated">
* <td>TLS_ECDH_ECDSA_WITH_RC4_128_SHA</td>
- * <td>11+</td>
- * <td>11-19</td>
+ * <td>11&ndash;22</td>
+ * <td>11&ndash;19</td>
* </tr>
- * <tr>
+ * <tr class="deprecated">
* <td>TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA</td>
- * <td>11+</td>
- * <td>11-19</td>
+ * <td>11&ndash;22</td>
+ * <td>11&ndash;19</td>
* </tr>
- * <tr>
+ * <tr class="deprecated">
* <td>TLS_ECDH_RSA_WITH_AES_128_CBC_SHA</td>
- * <td>11+</td>
- * <td>11-19</td>
+ * <td>11&ndash;22</td>
+ * <td>11&ndash;19</td>
* </tr>
- * <tr>
+ * <tr class="deprecated">
* <td>TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256</td>
- * <td>20+</td>
+ * <td>20&ndash;22</td>
* <td></td>
* </tr>
- * <tr>
+ * <tr class="deprecated">
* <td>TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256</td>
- * <td>20+</td>
+ * <td>20&ndash;22</td>
* <td></td>
* </tr>
- * <tr>
+ * <tr class="deprecated">
* <td>TLS_ECDH_RSA_WITH_AES_256_CBC_SHA</td>
- * <td>11+</td>
- * <td>11-19</td>
+ * <td>11&ndash;22</td>
+ * <td>11&ndash;19</td>
* </tr>
- * <tr>
+ * <tr class="deprecated">
* <td>TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384</td>
- * <td>20+</td>
+ * <td>20&ndash;22</td>
* <td></td>
* </tr>
- * <tr>
+ * <tr class="deprecated">
* <td>TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384</td>
- * <td>20+</td>
+ * <td>20&ndash;22</td>
* <td></td>
* </tr>
- * <tr>
+ * <tr class="deprecated">
* <td>TLS_ECDH_RSA_WITH_NULL_SHA</td>
- * <td>11+</td>
+ * <td>11&ndash;22</td>
* <td></td>
* </tr>
- * <tr>
+ * <tr class="deprecated">
* <td>TLS_ECDH_RSA_WITH_RC4_128_SHA</td>
- * <td>11+</td>
- * <td>11-19</td>
+ * <td>11&ndash;22</td>
+ * <td>11&ndash;19</td>
* </tr>
- * <tr>
+ * <tr class="deprecated">
* <td>TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA</td>
- * <td>11+</td>
+ * <td>11&ndash;22</td>
* <td></td>
* </tr>
- * <tr>
+ * <tr class="deprecated">
* <td>TLS_ECDH_anon_WITH_AES_128_CBC_SHA</td>
- * <td>11+</td>
+ * <td>11&ndash;22</td>
* <td></td>
* </tr>
- * <tr>
+ * <tr class="deprecated">
* <td>TLS_ECDH_anon_WITH_AES_256_CBC_SHA</td>
- * <td>11+</td>
+ * <td>11&ndash;22</td>
* <td></td>
* </tr>
- * <tr>
+ * <tr class="deprecated">
* <td>TLS_ECDH_anon_WITH_NULL_SHA</td>
- * <td>11+</td>
+ * <td>11&ndash;22</td>
* <td></td>
* </tr>
- * <tr>
+ * <tr class="deprecated">
* <td>TLS_ECDH_anon_WITH_RC4_128_SHA</td>
- * <td>11+</td>
+ * <td>11&ndash;22</td>
* <td></td>
* </tr>
* <tr>
@@ -525,9 +533,9 @@ import java.net.UnknownHostException;
* <td>21+</td>
* <td></td>
* </tr>
- * <tr>
+ * <tr class="deprecated">
* <td>TLS_PSK_WITH_3DES_EDE_CBC_SHA</td>
- * <td>21+</td>
+ * <td>21&ndash;22</td>
* <td></td>
* </tr>
* <tr>
@@ -575,9 +583,9 @@ import java.net.UnknownHostException;
* <td>20+</td>
* <td>20+</td>
* </tr>
- * <tr>
+ * <tr class="deprecated">
* <td>TLS_RSA_WITH_NULL_SHA256</td>
- * <td>20+</td>
+ * <td>20&ndash;22</td>
* <td></td>
* </tr>
* </tbody>
@@ -610,43 +618,43 @@ import java.net.UnknownHostException;
* <td>AES256-SHA</td>
* <td>TLS_RSA_WITH_AES_256_CBC_SHA</td>
* <td>1+</td>
- * <td>1-8, 11+</td>
+ * <td>1&ndash;8, 11+</td>
* </tr>
* <tr>
* <td>DES-CBC-MD5</td>
* <td>SSL_CK_DES_64_CBC_WITH_MD5</td>
- * <td>1-8</td>
- * <td>1-8</td>
+ * <td>1&ndash;8</td>
+ * <td>1&ndash;8</td>
* </tr>
- * <tr>
+ * <tr class="deprecated">
* <td>DES-CBC-SHA</td>
* <td>SSL_RSA_WITH_DES_CBC_SHA</td>
- * <td>1+</td>
- * <td>1-19</td>
+ * <td>1&ndash;22</td>
+ * <td>1&ndash;19</td>
* </tr>
* <tr>
* <td>DES-CBC3-MD5</td>
* <td>SSL_CK_DES_192_EDE3_CBC_WITH_MD5</td>
- * <td>1-8</td>
- * <td>1-8</td>
+ * <td>1&ndash;8</td>
+ * <td>1&ndash;8</td>
* </tr>
* <tr>
* <td>DES-CBC3-SHA</td>
* <td>SSL_RSA_WITH_3DES_EDE_CBC_SHA</td>
* <td>1+</td>
- * <td>1-19</td>
+ * <td>1&ndash;19</td>
* </tr>
- * <tr>
+ * <tr class="deprecated">
* <td>DHE-DSS-AES128-SHA</td>
* <td>TLS_DHE_DSS_WITH_AES_128_CBC_SHA</td>
- * <td>1+</td>
- * <td>1+</td>
+ * <td>1&ndash;22</td>
+ * <td>1&ndash;22</td>
* </tr>
- * <tr>
+ * <tr class="deprecated">
* <td>DHE-DSS-AES256-SHA</td>
* <td>TLS_DHE_DSS_WITH_AES_256_CBC_SHA</td>
- * <td>1+</td>
- * <td>1-8, 11+</td>
+ * <td>1&ndash;22</td>
+ * <td>1&ndash;8, 11&ndash;22</td>
* </tr>
* <tr>
* <td>DHE-RSA-AES128-SHA</td>
@@ -658,73 +666,73 @@ import java.net.UnknownHostException;
* <td>DHE-RSA-AES256-SHA</td>
* <td>TLS_DHE_RSA_WITH_AES_256_CBC_SHA</td>
* <td>1+</td>
- * <td>1-8, 11+</td>
+ * <td>1&ndash;8, 11+</td>
* </tr>
- * <tr>
+ * <tr class="deprecated">
* <td>EDH-DSS-DES-CBC-SHA</td>
* <td>SSL_DHE_DSS_WITH_DES_CBC_SHA</td>
- * <td>1+</td>
- * <td>1-19</td>
+ * <td>1&ndash;22</td>
+ * <td>1&ndash;19</td>
* </tr>
- * <tr>
+ * <tr class="deprecated">
* <td>EDH-DSS-DES-CBC3-SHA</td>
* <td>SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA</td>
- * <td>1+</td>
- * <td>1-19</td>
+ * <td>1&ndash;22</td>
+ * <td>1&ndash;19</td>
* </tr>
- * <tr>
+ * <tr class="deprecated">
* <td>EDH-RSA-DES-CBC-SHA</td>
* <td>SSL_DHE_RSA_WITH_DES_CBC_SHA</td>
- * <td>1+</td>
- * <td>1-19</td>
+ * <td>1&ndash;22</td>
+ * <td>1&ndash;19</td>
* </tr>
- * <tr>
+ * <tr class="deprecated">
* <td>EDH-RSA-DES-CBC3-SHA</td>
* <td>SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA</td>
- * <td>1+</td>
- * <td>1-19</td>
+ * <td>1&ndash;22</td>
+ * <td>1&ndash;19</td>
* </tr>
- * <tr>
+ * <tr class="deprecated">
* <td>EXP-DES-CBC-SHA</td>
* <td>SSL_RSA_EXPORT_WITH_DES40_CBC_SHA</td>
- * <td>1+</td>
- * <td>1-19</td>
+ * <td>1&ndash;22</td>
+ * <td>1&ndash;19</td>
* </tr>
- * <tr>
+ * <tr class="deprecated">
* <td>EXP-EDH-DSS-DES-CBC-SHA</td>
* <td>SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA</td>
- * <td>1+</td>
- * <td>1-19</td>
+ * <td>1&ndash;22</td>
+ * <td>1&ndash;19</td>
* </tr>
- * <tr>
+ * <tr class="deprecated">
* <td>EXP-EDH-RSA-DES-CBC-SHA</td>
* <td>SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA</td>
- * <td>1+</td>
- * <td>1-19</td>
+ * <td>1&ndash;22</td>
+ * <td>1&ndash;19</td>
* </tr>
* <tr>
* <td>EXP-RC2-CBC-MD5</td>
* <td>SSL_RSA_EXPORT_WITH_RC2_CBC_40_MD5</td>
- * <td>1-8</td>
- * <td>1-8</td>
+ * <td>1&ndash;8</td>
+ * <td>1&ndash;8</td>
* </tr>
- * <tr>
+ * <tr class="deprecated">
* <td>EXP-RC4-MD5</td>
* <td>SSL_RSA_EXPORT_WITH_RC4_40_MD5</td>
- * <td>1+</td>
- * <td>1-19</td>
+ * <td>1&ndash;22</td>
+ * <td>1&ndash;19</td>
* </tr>
* <tr>
* <td>RC2-CBC-MD5</td>
* <td>SSL_CK_RC2_128_CBC_WITH_MD5</td>
- * <td>1-8</td>
- * <td>1-8</td>
+ * <td>1&ndash;8</td>
+ * <td>1&ndash;8</td>
* </tr>
* <tr>
* <td>RC4-MD5</td>
* <td>SSL_RSA_WITH_RC4_128_MD5</td>
* <td>1+</td>
- * <td>1-19</td>
+ * <td>1&ndash;19</td>
* </tr>
* <tr>
* <td>RC4-SHA</td>
diff --git a/luni/src/main/java/javax/security/cert/X509Certificate.java b/luni/src/main/java/javax/security/cert/X509Certificate.java
index e85a556..5084ae0 100644
--- a/luni/src/main/java/javax/security/cert/X509Certificate.java
+++ b/luni/src/main/java/javax/security/cert/X509Certificate.java
@@ -51,7 +51,7 @@ public abstract class X509Certificate extends Certificate {
String classname = Security.getProperty("cert.provider.x509v1");
Class cl = Class.forName(classname);
constructor = cl.getConstructor(new Class[] {InputStream.class});
- } catch (Throwable e) {
+ } catch (Exception|LinkageError e) {
}
}
@@ -80,7 +80,7 @@ public abstract class X509Certificate extends Certificate {
try {
return (X509Certificate)
constructor.newInstance(new Object[] {inStream});
- } catch (Throwable e) {
+ } catch (ReflectiveOperationException e) {
throw new CertificateException(e.getMessage());
}
}
diff --git a/luni/src/main/java/javax/xml/datatype/FactoryFinder.java b/luni/src/main/java/javax/xml/datatype/FactoryFinder.java
index b65f412..1fbca2f 100644
--- a/luni/src/main/java/javax/xml/datatype/FactoryFinder.java
+++ b/luni/src/main/java/javax/xml/datatype/FactoryFinder.java
@@ -47,11 +47,30 @@ final class FactoryFinder {
/** <p>Debug flag to trace loading process.</p> */
private static boolean debug = false;
- /** <p>Cache properties for performance.</p> */
- private static Properties cacheProps = new Properties();
+ /**
+ * <p>Cache properties for performance. Use a static class to avoid double-checked
+ * locking.</p>
+ */
+ private static class CacheHolder {
- /** <p>First time requires initialization overhead.</p> */
- private static boolean firstTime = true;
+ private static Properties cacheProps = new Properties();
+
+ static {
+ String javah = System.getProperty("java.home");
+ String configFile = javah + File.separator + "lib" + File.separator + "jaxp.properties";
+ File f = new File(configFile);
+ if (f.exists()) {
+ if (debug) debugPrintln("Read properties file " + f);
+ try {
+ cacheProps.load(new FileInputStream(f));
+ } catch (Exception ex) {
+ if (debug) {
+ ex.printStackTrace();
+ }
+ }
+ }
+ }
+ }
/** Default columns per line. */
private static final int DEFAULT_LINE_LENGTH = 80;
@@ -177,22 +196,7 @@ final class FactoryFinder {
// try to read from $java.home/lib/jaxp.properties
try {
- String javah = System.getProperty("java.home");
- String configFile = javah + File.separator + "lib" + File.separator + "jaxp.properties";
- String factoryClassName = null;
- if (firstTime) {
- synchronized (cacheProps) {
- if (firstTime) {
- File f = new File(configFile);
- firstTime = false;
- if (f.exists()) {
- if (debug) debugPrintln("Read properties file " + f);
- cacheProps.load(new FileInputStream(f));
- }
- }
- }
- }
- factoryClassName = cacheProps.getProperty(factoryId);
+ String factoryClassName = CacheHolder.cacheProps.getProperty(factoryId);
if (debug) debugPrintln("found " + factoryClassName + " in $java.home/jaxp.properties");
if (factoryClassName != null) {
diff --git a/luni/src/main/java/javax/xml/validation/SchemaFactoryFinder.java b/luni/src/main/java/javax/xml/validation/SchemaFactoryFinder.java
index 636777c..0060612 100644
--- a/luni/src/main/java/javax/xml/validation/SchemaFactoryFinder.java
+++ b/luni/src/main/java/javax/xml/validation/SchemaFactoryFinder.java
@@ -49,14 +49,29 @@ final class SchemaFactoryFinder {
private static boolean debug = false;
/**
- * <p>Cache properties for performance.</p>
+ * <p>Cache properties for performance. Use a static class to avoid double-checked
+ * locking.</p>
*/
- private static Properties cacheProps = new Properties();
+ private static class CacheHolder {
- /**
- * <p>First time requires initialization overhead.</p>
- */
- private static boolean firstTime = true;
+ private static Properties cacheProps = new Properties();
+
+ static {
+ String javah = System.getProperty("java.home");
+ String configFile = javah + File.separator + "lib" + File.separator + "jaxp.properties";
+ File f = new File(configFile);
+ if (f.exists()) {
+ if (debug) debugPrintln("Read properties file " + f);
+ try {
+ cacheProps.load(new FileInputStream(f));
+ } catch (Exception ex) {
+ if (debug) {
+ ex.printStackTrace();
+ }
+ }
+ }
+ }
+ }
/**
* Default columns per line.
@@ -184,27 +199,9 @@ final class SchemaFactoryFinder {
}
}
- String javah = System.getProperty("java.home");
- String configFile = javah + File.separator +
- "lib" + File.separator + "jaxp.properties";
-
- String factoryClassName = null ;
-
// try to read from $java.home/lib/jaxp.properties
try {
- if(firstTime){
- synchronized(cacheProps){
- if(firstTime){
- File f=new File( configFile );
- firstTime = false;
- if(f.exists()){
- if (debug) debugPrintln("Read properties file " + f);
- cacheProps.load(new FileInputStream(f));
- }
- }
- }
- }
- factoryClassName = cacheProps.getProperty(propertyName);
+ String factoryClassName = CacheHolder.cacheProps.getProperty(propertyName);
if (debug) debugPrintln("found " + factoryClassName + " in $java.home/jaxp.properties");
if (factoryClassName != null) {
diff --git a/luni/src/main/java/javax/xml/xpath/XPathFactoryFinder.java b/luni/src/main/java/javax/xml/xpath/XPathFactoryFinder.java
index 0113e7d..5a7663c 100644
--- a/luni/src/main/java/javax/xml/xpath/XPathFactoryFinder.java
+++ b/luni/src/main/java/javax/xml/xpath/XPathFactoryFinder.java
@@ -56,14 +56,29 @@ final class XPathFactoryFinder {
}
/**
- * <p>Cache properties for performance.</p>
+ * <p>Cache properties for performance. Use a static class to avoid double-checked
+ * locking.</p>
*/
- private static Properties cacheProps = new Properties();
+ private static class CacheHolder {
- /**
- * <p>First time requires initialization overhead.</p>
- */
- private static boolean firstTime = true;
+ private static Properties cacheProps = new Properties();
+
+ static {
+ String javah = System.getProperty("java.home");
+ String configFile = javah + File.separator + "lib" + File.separator + "jaxp.properties";
+ File f = new File(configFile);
+ if (f.exists()) {
+ if (debug) debugPrintln("Read properties file " + f);
+ try {
+ cacheProps.load(new FileInputStream(f));
+ } catch (Exception ex) {
+ if (debug) {
+ ex.printStackTrace();
+ }
+ }
+ }
+ }
+ }
/**
* <p>Conditional debug printing.</p>
@@ -164,27 +179,9 @@ final class XPathFactoryFinder {
e.printStackTrace();
}
- String javah = System.getProperty("java.home");
- String configFile = javah + File.separator +
- "lib" + File.separator + "jaxp.properties";
-
- String factoryClassName = null ;
-
// try to read from $java.home/lib/jaxp.properties
try {
- if(firstTime){
- synchronized(cacheProps){
- if(firstTime){
- File f=new File( configFile );
- firstTime = false;
- if (f.exists()) {
- if (debug) debugPrintln("Read properties file " + f);
- cacheProps.load(new FileInputStream(f));
- }
- }
- }
- }
- factoryClassName = cacheProps.getProperty(propertyName);
+ String factoryClassName = CacheHolder.cacheProps.getProperty(propertyName);
if (debug) debugPrintln("found " + factoryClassName + " in $java.home/jaxp.properties");
if (factoryClassName != null) {
diff --git a/luni/src/main/java/libcore/icu/DateIntervalFormat.java b/luni/src/main/java/libcore/icu/DateIntervalFormat.java
index 3855654..7e7ad01 100644
--- a/luni/src/main/java/libcore/icu/DateIntervalFormat.java
+++ b/luni/src/main/java/libcore/icu/DateIntervalFormat.java
@@ -16,48 +16,27 @@
package libcore.icu;
-import java.util.Calendar;
-import java.util.Locale;
+import com.ibm.icu.util.Calendar;
+import com.ibm.icu.util.ULocale;
+
+import java.text.FieldPosition;
import java.util.TimeZone;
import libcore.util.BasicLruCache;
+import static libcore.icu.DateUtilsBridge.FORMAT_UTC;
+
/**
- * Exposes icu4c's DateIntervalFormat.
+ * Exposes icu4j's DateIntervalFormat.
*/
public final class DateIntervalFormat {
- // These are all public API in DateUtils. There are others, but they're either for use with
- // other methods (like FORMAT_ABBREV_RELATIVE), don't internationalize (like FORMAT_CAP_AMPM),
- // or have never been implemented anyway.
- public static final int FORMAT_SHOW_TIME = 0x00001;
- public static final int FORMAT_SHOW_WEEKDAY = 0x00002;
- public static final int FORMAT_SHOW_YEAR = 0x00004;
- public static final int FORMAT_NO_YEAR = 0x00008;
- public static final int FORMAT_SHOW_DATE = 0x00010;
- public static final int FORMAT_NO_MONTH_DAY = 0x00020;
- public static final int FORMAT_12HOUR = 0x00040;
- public static final int FORMAT_24HOUR = 0x00080;
- public static final int FORMAT_UTC = 0x02000;
- public static final int FORMAT_ABBREV_TIME = 0x04000;
- public static final int FORMAT_ABBREV_WEEKDAY = 0x08000;
- public static final int FORMAT_ABBREV_MONTH = 0x10000;
- public static final int FORMAT_NUMERIC_DATE = 0x20000;
- public static final int FORMAT_ABBREV_ALL = 0x80000;
-
- private static final int DAY_IN_MS = 24 * 60 * 60 * 1000;
- private static final int EPOCH_JULIAN_DAY = 2440588;
-
private static final FormatterCache CACHED_FORMATTERS = new FormatterCache();
- static class FormatterCache extends BasicLruCache<String, Long> {
+ static class FormatterCache extends BasicLruCache<String, com.ibm.icu.text.DateIntervalFormat> {
FormatterCache() {
super(8);
}
-
- protected void entryEvicted(String key, Long value) {
- destroyDateIntervalFormat(value);
- }
- };
+ }
private DateIntervalFormat() {
}
@@ -67,131 +46,58 @@ public final class DateIntervalFormat {
if ((flags & FORMAT_UTC) != 0) {
olsonId = "UTC";
}
+ // We create a java.util.TimeZone here to use libcore's data and libcore's olson ID / pseudo-tz
+ // logic.
TimeZone tz = (olsonId != null) ? TimeZone.getTimeZone(olsonId) : TimeZone.getDefault();
- return formatDateRange(Locale.getDefault(), tz, startMs, endMs, flags);
+ com.ibm.icu.util.TimeZone icuTimeZone = DateUtilsBridge.icuTimeZone(tz);
+ ULocale icuLocale = ULocale.getDefault();
+ return formatDateRange(icuLocale, icuTimeZone, startMs, endMs, flags);
}
// This is our slightly more sensible internal API. (A truly sane replacement would take a
// skeleton instead of int flags.)
- public static String formatDateRange(Locale locale, TimeZone tz, long startMs, long endMs, int flags) {
- Calendar startCalendar = Calendar.getInstance(tz);
- startCalendar.setTimeInMillis(startMs);
-
+ public static String formatDateRange(ULocale icuLocale, com.ibm.icu.util.TimeZone icuTimeZone,
+ long startMs, long endMs, int flags) {
+ Calendar startCalendar = DateUtilsBridge.createIcuCalendar(icuTimeZone, icuLocale, startMs);
Calendar endCalendar;
if (startMs == endMs) {
endCalendar = startCalendar;
} else {
- endCalendar = Calendar.getInstance(tz);
- endCalendar.setTimeInMillis(endMs);
+ endCalendar = DateUtilsBridge.createIcuCalendar(icuTimeZone, icuLocale, endMs);
}
boolean endsAtMidnight = isMidnight(endCalendar);
// If we're not showing the time or the start and end times are on the same day, and the
// end time is midnight, fudge the end date so we don't count the day that's about to start.
- // This is not the behavior of icu4c's DateIntervalFormat, but it's the historical behavior
+ // This is not the behavior of icu4j's DateIntervalFormat, but it's the historical behavior
// of Android's DateUtils.formatDateRange.
if (startMs != endMs && endsAtMidnight &&
- ((flags & FORMAT_SHOW_TIME) == 0 || dayDistance(startCalendar, endCalendar) <= 1)) {
- endCalendar.roll(Calendar.DAY_OF_MONTH, false);
- endMs -= DAY_IN_MS;
+ ((flags & DateUtilsBridge.FORMAT_SHOW_TIME) == 0
+ || DateUtilsBridge.dayDistance(startCalendar, endCalendar) <= 1)) {
+ endCalendar.add(Calendar.DAY_OF_MONTH, -1);
}
- String skeleton = toSkeleton(startCalendar, endCalendar, flags);
+ String skeleton = DateUtilsBridge.toSkeleton(startCalendar, endCalendar, flags);
synchronized (CACHED_FORMATTERS) {
- return formatDateInterval(getFormatter(skeleton, locale.toString(), tz.getID()), startMs, endMs);
+ com.ibm.icu.text.DateIntervalFormat formatter =
+ getFormatter(skeleton, icuLocale, icuTimeZone);
+ return formatter.format(startCalendar, endCalendar, new StringBuffer(),
+ new FieldPosition(0)).toString();
}
}
- private static long getFormatter(String skeleton, String localeName, String tzName) {
- String key = skeleton + "\t" + localeName + "\t" + tzName;
- Long formatter = CACHED_FORMATTERS.get(key);
+ private static com.ibm.icu.text.DateIntervalFormat getFormatter(String skeleton, ULocale locale,
+ com.ibm.icu.util.TimeZone icuTimeZone) {
+ String key = skeleton + "\t" + locale + "\t" + icuTimeZone;
+ com.ibm.icu.text.DateIntervalFormat formatter = CACHED_FORMATTERS.get(key);
if (formatter != null) {
return formatter;
}
- long address = createDateIntervalFormat(skeleton, localeName, tzName);
- CACHED_FORMATTERS.put(key, address);
- return address;
- }
-
- private static String toSkeleton(Calendar startCalendar, Calendar endCalendar, int flags) {
- if ((flags & FORMAT_ABBREV_ALL) != 0) {
- flags |= FORMAT_ABBREV_MONTH | FORMAT_ABBREV_TIME | FORMAT_ABBREV_WEEKDAY;
- }
-
- String monthPart = "MMMM";
- if ((flags & FORMAT_NUMERIC_DATE) != 0) {
- monthPart = "M";
- } else if ((flags & FORMAT_ABBREV_MONTH) != 0) {
- monthPart = "MMM";
- }
-
- String weekPart = "EEEE";
- if ((flags & FORMAT_ABBREV_WEEKDAY) != 0) {
- weekPart = "EEE";
- }
-
- String timePart = "j"; // "j" means choose 12 or 24 hour based on current locale.
- if ((flags & FORMAT_24HOUR) != 0) {
- timePart = "H";
- } else if ((flags & FORMAT_12HOUR) != 0) {
- timePart = "h";
- }
-
- // If we've not been asked to abbreviate times, or we're using the 24-hour clock (where it
- // never makes sense to leave out the minutes), include minutes. This gets us times like
- // "4 PM" while avoiding times like "16" (for "16:00").
- if ((flags & FORMAT_ABBREV_TIME) == 0 || (flags & FORMAT_24HOUR) != 0) {
- timePart += "m";
- } else {
- // Otherwise, we're abbreviating a 12-hour time, and should only show the minutes
- // if they're not both "00".
- if (!(onTheHour(startCalendar) && onTheHour(endCalendar))) {
- timePart = timePart + "m";
- }
- }
-
- if (fallOnDifferentDates(startCalendar, endCalendar)) {
- flags |= FORMAT_SHOW_DATE;
- }
-
- if (fallInSameMonth(startCalendar, endCalendar) && (flags & FORMAT_NO_MONTH_DAY) != 0) {
- flags &= (~FORMAT_SHOW_WEEKDAY);
- flags &= (~FORMAT_SHOW_TIME);
- }
-
- if ((flags & (FORMAT_SHOW_DATE | FORMAT_SHOW_TIME | FORMAT_SHOW_WEEKDAY)) == 0) {
- flags |= FORMAT_SHOW_DATE;
- }
-
- // If we've been asked to show the date, work out whether we think we should show the year.
- if ((flags & FORMAT_SHOW_DATE) != 0) {
- if ((flags & FORMAT_SHOW_YEAR) != 0) {
- // The caller explicitly wants us to show the year.
- } else if ((flags & FORMAT_NO_YEAR) != 0) {
- // The caller explicitly doesn't want us to show the year, even if we otherwise would.
- } else if (!fallInSameYear(startCalendar, endCalendar) || !isThisYear(startCalendar)) {
- flags |= FORMAT_SHOW_YEAR;
- }
- }
-
- StringBuilder builder = new StringBuilder();
- if ((flags & (FORMAT_SHOW_DATE | FORMAT_NO_MONTH_DAY)) != 0) {
- if ((flags & FORMAT_SHOW_YEAR) != 0) {
- builder.append("y");
- }
- builder.append(monthPart);
- if ((flags & FORMAT_NO_MONTH_DAY) == 0) {
- builder.append("d");
- }
- }
- if ((flags & FORMAT_SHOW_WEEKDAY) != 0) {
- builder.append(weekPart);
- }
- if ((flags & FORMAT_SHOW_TIME) != 0) {
- builder.append(timePart);
- }
- return builder.toString();
+ formatter = com.ibm.icu.text.DateIntervalFormat.getInstance(skeleton, locale);
+ formatter.setTimeZone(icuTimeZone);
+ CACHED_FORMATTERS.put(key, formatter);
+ return formatter;
}
private static boolean isMidnight(Calendar c) {
@@ -201,39 +107,4 @@ public final class DateIntervalFormat {
c.get(Calendar.MILLISECOND) == 0;
}
- private static boolean onTheHour(Calendar c) {
- return c.get(Calendar.MINUTE) == 0 && c.get(Calendar.SECOND) == 0;
- }
-
- private static boolean fallOnDifferentDates(Calendar c1, Calendar c2) {
- return c1.get(Calendar.YEAR) != c2.get(Calendar.YEAR) ||
- c1.get(Calendar.MONTH) != c2.get(Calendar.MONTH) ||
- c1.get(Calendar.DAY_OF_MONTH) != c2.get(Calendar.DAY_OF_MONTH);
- }
-
- private static boolean fallInSameMonth(Calendar c1, Calendar c2) {
- return c1.get(Calendar.MONTH) == c2.get(Calendar.MONTH);
- }
-
- private static boolean fallInSameYear(Calendar c1, Calendar c2) {
- return c1.get(Calendar.YEAR) == c2.get(Calendar.YEAR);
- }
-
- private static boolean isThisYear(Calendar c) {
- Calendar now = Calendar.getInstance(c.getTimeZone());
- return c.get(Calendar.YEAR) == now.get(Calendar.YEAR);
- }
-
- private static int dayDistance(Calendar c1, Calendar c2) {
- return julianDay(c2) - julianDay(c1);
- }
-
- private static int julianDay(Calendar c) {
- long utcMs = c.getTimeInMillis() + c.get(Calendar.ZONE_OFFSET) + c.get(Calendar.DST_OFFSET);
- return (int) (utcMs / DAY_IN_MS) + EPOCH_JULIAN_DAY;
- }
-
- private static native long createDateIntervalFormat(String skeleton, String localeName, String tzName);
- private static native void destroyDateIntervalFormat(long address);
- private static native String formatDateInterval(long address, long fromDate, long toDate);
}
diff --git a/luni/src/main/java/libcore/icu/DateTimeFormat.java b/luni/src/main/java/libcore/icu/DateTimeFormat.java
new file mode 100644
index 0000000..7323c26
--- /dev/null
+++ b/luni/src/main/java/libcore/icu/DateTimeFormat.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package libcore.icu;
+
+import com.ibm.icu.text.DateFormat;
+import com.ibm.icu.text.DateTimePatternGenerator;
+import com.ibm.icu.text.DisplayContext;
+import com.ibm.icu.text.SimpleDateFormat;
+import com.ibm.icu.util.Calendar;
+import com.ibm.icu.util.ULocale;
+
+import libcore.util.BasicLruCache;
+
+/**
+ * A formatter that outputs a single date/time.
+ */
+public class DateTimeFormat {
+ private static final FormatterCache CACHED_FORMATTERS = new FormatterCache();
+
+ static class FormatterCache extends BasicLruCache<String, DateFormat> {
+ FormatterCache() {
+ super(8);
+ }
+ }
+
+ private DateTimeFormat() {
+ }
+
+ public static String format(ULocale icuLocale, Calendar time, int flags,
+ DisplayContext displayContext) {
+ String skeleton = DateUtilsBridge.toSkeleton(time, flags);
+ String key = skeleton + "\t" + icuLocale + "\t" + time.getTimeZone();
+ synchronized(CACHED_FORMATTERS) {
+ DateFormat formatter = CACHED_FORMATTERS.get(key);
+ if (formatter == null) {
+ DateTimePatternGenerator generator = DateTimePatternGenerator.getInstance(icuLocale);
+ formatter = new SimpleDateFormat(generator.getBestPattern(skeleton), icuLocale);
+ CACHED_FORMATTERS.put(key, formatter);
+ }
+ formatter.setContext(displayContext);
+ return formatter.format(time);
+ }
+ }
+}
diff --git a/luni/src/main/java/libcore/icu/DateUtilsBridge.java b/luni/src/main/java/libcore/icu/DateUtilsBridge.java
new file mode 100644
index 0000000..88faa90
--- /dev/null
+++ b/luni/src/main/java/libcore/icu/DateUtilsBridge.java
@@ -0,0 +1,177 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package libcore.icu;
+
+import com.ibm.icu.impl.JavaTimeZone;
+import com.ibm.icu.util.Calendar;
+import com.ibm.icu.util.GregorianCalendar;
+import com.ibm.icu.util.ULocale;
+
+/**
+ * Common methods and constants for the various ICU formatters used to support
+ * android.text.format.DateUtils.
+ */
+public final class DateUtilsBridge {
+ // These are all public API in DateUtils. There are others, but they're either for use with
+ // other methods (like FORMAT_ABBREV_RELATIVE), don't internationalize (like FORMAT_CAP_AMPM),
+ // or have never been implemented anyway.
+ public static final int FORMAT_SHOW_TIME = 0x00001;
+ public static final int FORMAT_SHOW_WEEKDAY = 0x00002;
+ public static final int FORMAT_SHOW_YEAR = 0x00004;
+ public static final int FORMAT_NO_YEAR = 0x00008;
+ public static final int FORMAT_SHOW_DATE = 0x00010;
+ public static final int FORMAT_NO_MONTH_DAY = 0x00020;
+ public static final int FORMAT_12HOUR = 0x00040;
+ public static final int FORMAT_24HOUR = 0x00080;
+ public static final int FORMAT_UTC = 0x02000;
+ public static final int FORMAT_ABBREV_TIME = 0x04000;
+ public static final int FORMAT_ABBREV_WEEKDAY = 0x08000;
+ public static final int FORMAT_ABBREV_MONTH = 0x10000;
+ public static final int FORMAT_NUMERIC_DATE = 0x20000;
+ public static final int FORMAT_ABBREV_RELATIVE = 0x40000;
+ public static final int FORMAT_ABBREV_ALL = 0x80000;
+
+ /**
+ * Creates an immutable ICU timezone backed by the specified libcore timezone data. At the time of
+ * writing the libcore implementation is faster but restricted to 1902 - 2038.
+ * Callers must not modify the {@code tz} after calling this method.
+ */
+ public static com.ibm.icu.util.TimeZone icuTimeZone(java.util.TimeZone tz) {
+ JavaTimeZone javaTimeZone = new JavaTimeZone(tz, null);
+ javaTimeZone.freeze(); // Optimization - allows the timezone to be copied cheaply.
+ return javaTimeZone;
+ }
+
+ public static Calendar createIcuCalendar(com.ibm.icu.util.TimeZone icuTimeZone, ULocale icuLocale,
+ long timeInMillis) {
+ Calendar calendar = new GregorianCalendar(icuTimeZone, icuLocale);
+ calendar.setTimeInMillis(timeInMillis);
+ return calendar;
+ }
+
+ public static String toSkeleton(Calendar calendar, int flags) {
+ return toSkeleton(calendar, calendar, flags);
+ }
+
+ public static String toSkeleton(Calendar startCalendar, Calendar endCalendar, int flags) {
+ if ((flags & FORMAT_ABBREV_ALL) != 0) {
+ flags |= FORMAT_ABBREV_MONTH | FORMAT_ABBREV_TIME | FORMAT_ABBREV_WEEKDAY;
+ }
+
+ String monthPart = "MMMM";
+ if ((flags & FORMAT_NUMERIC_DATE) != 0) {
+ monthPart = "M";
+ } else if ((flags & FORMAT_ABBREV_MONTH) != 0) {
+ monthPart = "MMM";
+ }
+
+ String weekPart = "EEEE";
+ if ((flags & FORMAT_ABBREV_WEEKDAY) != 0) {
+ weekPart = "EEE";
+ }
+
+ String timePart = "j"; // "j" means choose 12 or 24 hour based on current locale.
+ if ((flags & FORMAT_24HOUR) != 0) {
+ timePart = "H";
+ } else if ((flags & FORMAT_12HOUR) != 0) {
+ timePart = "h";
+ }
+
+ // If we've not been asked to abbreviate times, or we're using the 24-hour clock (where it
+ // never makes sense to leave out the minutes), include minutes. This gets us times like
+ // "4 PM" while avoiding times like "16" (for "16:00").
+ if ((flags & FORMAT_ABBREV_TIME) == 0 || (flags & FORMAT_24HOUR) != 0) {
+ timePart += "m";
+ } else {
+ // Otherwise, we're abbreviating a 12-hour time, and should only show the minutes
+ // if they're not both "00".
+ if (!(onTheHour(startCalendar) && onTheHour(endCalendar))) {
+ timePart = timePart + "m";
+ }
+ }
+
+ if (fallOnDifferentDates(startCalendar, endCalendar)) {
+ flags |= FORMAT_SHOW_DATE;
+ }
+
+ if (fallInSameMonth(startCalendar, endCalendar) && (flags & FORMAT_NO_MONTH_DAY) != 0) {
+ flags &= (~FORMAT_SHOW_WEEKDAY);
+ flags &= (~FORMAT_SHOW_TIME);
+ }
+
+ if ((flags & (FORMAT_SHOW_DATE | FORMAT_SHOW_TIME | FORMAT_SHOW_WEEKDAY)) == 0) {
+ flags |= FORMAT_SHOW_DATE;
+ }
+
+ // If we've been asked to show the date, work out whether we think we should show the year.
+ if ((flags & FORMAT_SHOW_DATE) != 0) {
+ if ((flags & FORMAT_SHOW_YEAR) != 0) {
+ // The caller explicitly wants us to show the year.
+ } else if ((flags & FORMAT_NO_YEAR) != 0) {
+ // The caller explicitly doesn't want us to show the year, even if we otherwise would.
+ } else if (!fallInSameYear(startCalendar, endCalendar) || !isThisYear(startCalendar)) {
+ flags |= FORMAT_SHOW_YEAR;
+ }
+ }
+
+ StringBuilder builder = new StringBuilder();
+ if ((flags & (FORMAT_SHOW_DATE | FORMAT_NO_MONTH_DAY)) != 0) {
+ if ((flags & FORMAT_SHOW_YEAR) != 0) {
+ builder.append("y");
+ }
+ builder.append(monthPart);
+ if ((flags & FORMAT_NO_MONTH_DAY) == 0) {
+ builder.append("d");
+ }
+ }
+ if ((flags & FORMAT_SHOW_WEEKDAY) != 0) {
+ builder.append(weekPart);
+ }
+ if ((flags & FORMAT_SHOW_TIME) != 0) {
+ builder.append(timePart);
+ }
+ return builder.toString();
+ }
+
+ public static int dayDistance(Calendar c1, Calendar c2) {
+ return c2.get(Calendar.JULIAN_DAY) - c1.get(Calendar.JULIAN_DAY);
+ }
+
+ private static boolean onTheHour(Calendar c) {
+ return c.get(Calendar.MINUTE) == 0 && c.get(Calendar.SECOND) == 0;
+ }
+
+ private static boolean fallOnDifferentDates(Calendar c1, Calendar c2) {
+ return c1.get(Calendar.YEAR) != c2.get(Calendar.YEAR) ||
+ c1.get(Calendar.MONTH) != c2.get(Calendar.MONTH) ||
+ c1.get(Calendar.DAY_OF_MONTH) != c2.get(Calendar.DAY_OF_MONTH);
+ }
+
+ private static boolean fallInSameMonth(Calendar c1, Calendar c2) {
+ return c1.get(Calendar.MONTH) == c2.get(Calendar.MONTH);
+ }
+
+ private static boolean fallInSameYear(Calendar c1, Calendar c2) {
+ return c1.get(Calendar.YEAR) == c2.get(Calendar.YEAR);
+ }
+
+ private static boolean isThisYear(Calendar c) {
+ Calendar now = (Calendar) c.clone();
+ now.setTimeInMillis(System.currentTimeMillis());
+ return c.get(Calendar.YEAR) == now.get(Calendar.YEAR);
+ }
+}
diff --git a/luni/src/main/java/libcore/icu/ICU.java b/luni/src/main/java/libcore/icu/ICU.java
index 0ef3f93..42def54 100644
--- a/luni/src/main/java/libcore/icu/ICU.java
+++ b/luni/src/main/java/libcore/icu/ICU.java
@@ -457,4 +457,7 @@ public final class ICU {
* Returns a locale name, not a BCP-47 language tag. e.g. en_US not en-US.
*/
public static native String getDefaultLocale();
+
+ /** Returns the TZData version as reported by ICU4C. */
+ public static native String getTZDataVersion();
}
diff --git a/luni/src/main/java/libcore/icu/LocaleData.java b/luni/src/main/java/libcore/icu/LocaleData.java
index cca38e1..cf52b9c 100644
--- a/luni/src/main/java/libcore/icu/LocaleData.java
+++ b/luni/src/main/java/libcore/icu/LocaleData.java
@@ -88,15 +88,12 @@ public final class LocaleData {
public String shortDateFormat4;
// Used by DateFormat to implement 12- and 24-hour SHORT and MEDIUM.
+ // The first two are also used directly by frameworks code.
public String timeFormat_hm;
public String timeFormat_Hm;
public String timeFormat_hms;
public String timeFormat_Hms;
- // Used by android.text.format.DateFormat.getTimeFormat.
- public String timeFormat12; // "hh:mm a"
- public String timeFormat24; // "HH:mm"
-
// Used by DecimalFormatSymbols.
public char zeroDigit;
public char decimalSeparator;
@@ -213,12 +210,6 @@ public final class LocaleData {
localeData.timeFormat_Hm = ICU.getBestDateTimePattern("Hm", locale);
localeData.timeFormat_hms = ICU.getBestDateTimePattern("hms", locale);
localeData.timeFormat_Hms = ICU.getBestDateTimePattern("Hms", locale);
- // We could move callers over to the other fields, but these seem simpler and discourage
- // people from shooting themselves in the foot by learning about patterns and skeletons.
- // TODO: the right fix here is probably to move callers over to java.text.DateFormat,
- // so nothing outside libcore references these any more.
- localeData.timeFormat12 = localeData.timeFormat_hm;
- localeData.timeFormat24 = localeData.timeFormat_Hm;
// Fix up a couple of patterns.
if (localeData.fullTimeFormat != null) {
diff --git a/luni/src/main/java/libcore/icu/NativeBreakIterator.java b/luni/src/main/java/libcore/icu/NativeBreakIterator.java
deleted file mode 100644
index 992aac2..0000000
--- a/luni/src/main/java/libcore/icu/NativeBreakIterator.java
+++ /dev/null
@@ -1,177 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package libcore.icu;
-
-import java.text.CharacterIterator;
-import java.text.StringCharacterIterator;
-import java.util.Locale;
-
-public final class NativeBreakIterator implements Cloneable {
- // Acceptable values for the 'type' field.
- private static final int BI_CHAR_INSTANCE = 1;
- private static final int BI_WORD_INSTANCE = 2;
- private static final int BI_LINE_INSTANCE = 3;
- private static final int BI_SENT_INSTANCE = 4;
-
- // The address of the native peer.
- // Uses of this must be manually synchronized to avoid native crashes.
- private final long address;
-
- private final int type;
- private String string;
- private CharacterIterator charIterator;
-
- private NativeBreakIterator(long address, int type) {
- this.address = address;
- this.type = type;
- this.charIterator = new StringCharacterIterator("");
- }
-
- @Override
- public Object clone() {
- long cloneAddr = cloneImpl(this.address);
- NativeBreakIterator clone = new NativeBreakIterator(cloneAddr, this.type);
- clone.string = this.string;
- // The RI doesn't clone the CharacterIterator.
- clone.charIterator = this.charIterator;
- return clone;
- }
-
- @Override
- public boolean equals(Object object) {
- if (object == this) {
- return true;
- }
- if (!(object instanceof NativeBreakIterator)) {
- return false;
- }
- // TODO: is this sufficient? shouldn't we be checking the underlying rules?
- NativeBreakIterator rhs = (NativeBreakIterator) object;
- return type == rhs.type && charIterator.equals(rhs.charIterator);
- }
-
- @Override
- public int hashCode() {
- return 42; // No-one uses BreakIterator as a hash key.
- }
-
- @Override protected void finalize() throws Throwable {
- try {
- closeImpl(this.address);
- } finally {
- super.finalize();
- }
- }
-
- public int current() {
- return currentImpl(this.address, this.string);
- }
-
- public int first() {
- return firstImpl(this.address, this.string);
- }
-
- public int following(int offset) {
- return followingImpl(this.address, this.string, offset);
- }
-
- public CharacterIterator getText() {
- int newLocation = currentImpl(this.address, this.string);
- this.charIterator.setIndex(newLocation);
- return this.charIterator;
- }
-
- public int last() {
- return lastImpl(this.address, this.string);
- }
-
- public int next(int n) {
- return nextImpl(this.address, this.string, n);
- }
-
- public int next() {
- return nextImpl(this.address, this.string, 1);
- }
-
- public int previous() {
- return previousImpl(this.address, this.string);
- }
-
- public void setText(CharacterIterator newText) {
- StringBuilder sb = new StringBuilder();
- for (char c = newText.first(); c != CharacterIterator.DONE; c = newText.next()) {
- sb.append(c);
- }
- setText(sb.toString(), newText);
- }
-
- public void setText(String newText) {
- setText(newText, new StringCharacterIterator(newText));
- }
-
- private void setText(String s, CharacterIterator it) {
- this.string = s;
- this.charIterator = it;
- setTextImpl(this.address, this.string);
- }
-
- public boolean hasText() {
- return (string != null);
- }
-
- public boolean isBoundary(int offset) {
- return isBoundaryImpl(this.address, this.string, offset);
- }
-
- public int preceding(int offset) {
- return precedingImpl(this.address, this.string, offset);
- }
-
- public static NativeBreakIterator getCharacterInstance(Locale locale) {
- return new NativeBreakIterator(getCharacterInstanceImpl(locale.toLanguageTag()), BI_CHAR_INSTANCE);
- }
-
- public static NativeBreakIterator getLineInstance(Locale locale) {
- return new NativeBreakIterator(getLineInstanceImpl(locale.toLanguageTag()), BI_LINE_INSTANCE);
- }
-
- public static NativeBreakIterator getSentenceInstance(Locale locale) {
- return new NativeBreakIterator(getSentenceInstanceImpl(locale.toLanguageTag()), BI_SENT_INSTANCE);
- }
-
- public static NativeBreakIterator getWordInstance(Locale locale) {
- return new NativeBreakIterator(getWordInstanceImpl(locale.toLanguageTag()), BI_WORD_INSTANCE);
- }
-
- private static native long getCharacterInstanceImpl(String locale);
- private static native long getWordInstanceImpl(String locale);
- private static native long getLineInstanceImpl(String locale);
- private static native long getSentenceInstanceImpl(String locale);
- private static synchronized native long cloneImpl(long address);
-
- private static synchronized native void closeImpl(long address);
-
- private static synchronized native void setTextImpl(long address, String text);
- private static synchronized native int precedingImpl(long address, String text, int offset);
- private static synchronized native boolean isBoundaryImpl(long address, String text, int offset);
- private static synchronized native int nextImpl(long address, String text, int n);
- private static synchronized native int previousImpl(long address, String text);
- private static synchronized native int currentImpl(long address, String text);
- private static synchronized native int firstImpl(long address, String text);
- private static synchronized native int followingImpl(long address, String text, int offset);
- private static synchronized native int lastImpl(long address, String text);
-}
diff --git a/luni/src/main/java/libcore/icu/RelativeDateTimeFormatter.java b/luni/src/main/java/libcore/icu/RelativeDateTimeFormatter.java
new file mode 100644
index 0000000..e2afa61
--- /dev/null
+++ b/luni/src/main/java/libcore/icu/RelativeDateTimeFormatter.java
@@ -0,0 +1,360 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package libcore.icu;
+
+import java.util.Locale;
+import libcore.util.BasicLruCache;
+
+import com.ibm.icu.text.DisplayContext;
+import com.ibm.icu.util.Calendar;
+import com.ibm.icu.util.ULocale;
+
+import static libcore.icu.DateUtilsBridge.FORMAT_ABBREV_ALL;
+import static libcore.icu.DateUtilsBridge.FORMAT_ABBREV_MONTH;
+import static libcore.icu.DateUtilsBridge.FORMAT_ABBREV_RELATIVE;
+import static libcore.icu.DateUtilsBridge.FORMAT_NO_YEAR;
+import static libcore.icu.DateUtilsBridge.FORMAT_NUMERIC_DATE;
+import static libcore.icu.DateUtilsBridge.FORMAT_SHOW_DATE;
+import static libcore.icu.DateUtilsBridge.FORMAT_SHOW_TIME;
+import static libcore.icu.DateUtilsBridge.FORMAT_SHOW_YEAR;
+
+/**
+ * Exposes icu4j's RelativeDateTimeFormatter.
+ */
+public final class RelativeDateTimeFormatter {
+
+ public static final long SECOND_IN_MILLIS = 1000;
+ public static final long MINUTE_IN_MILLIS = SECOND_IN_MILLIS * 60;
+ public static final long HOUR_IN_MILLIS = MINUTE_IN_MILLIS * 60;
+ public static final long DAY_IN_MILLIS = HOUR_IN_MILLIS * 24;
+ public static final long WEEK_IN_MILLIS = DAY_IN_MILLIS * 7;
+ // YEAR_IN_MILLIS considers 364 days as a year. However, since this
+ // constant comes from public API in DateUtils, it cannot be fixed here.
+ public static final long YEAR_IN_MILLIS = WEEK_IN_MILLIS * 52;
+
+ private static final int DAY_IN_MS = 24 * 60 * 60 * 1000;
+ private static final int EPOCH_JULIAN_DAY = 2440588;
+
+ private static final FormatterCache CACHED_FORMATTERS = new FormatterCache();
+
+ static class FormatterCache
+ extends BasicLruCache<String, com.ibm.icu.text.RelativeDateTimeFormatter> {
+ FormatterCache() {
+ super(8);
+ }
+ }
+
+ private RelativeDateTimeFormatter() {
+ }
+
+ /**
+ * This is the internal API that implements the functionality of
+ * DateUtils.getRelativeTimeSpanString(long, long, long, int), which is to
+ * return a string describing 'time' as a time relative to 'now' such as
+ * '5 minutes ago', or 'in 2 days'. More examples can be found in DateUtils'
+ * doc.
+ *
+ * In the implementation below, it selects the appropriate time unit based on
+ * the elapsed time between time' and 'now', e.g. minutes, days and etc.
+ * Callers may also specify the desired minimum resolution to show in the
+ * result. For example, '45 minutes ago' will become '0 hours ago' when
+ * minResolution is HOUR_IN_MILLIS. Once getting the quantity and unit to
+ * display, it calls icu4j's RelativeDateTimeFormatter to format the actual
+ * string according to the given locale.
+ *
+ * Note that when minResolution is set to DAY_IN_MILLIS, it returns the
+ * result depending on the actual date difference. For example, it will
+ * return 'Yesterday' even if 'time' was less than 24 hours ago but falling
+ * onto a different calendar day.
+ *
+ * It takes two additional parameters of Locale and TimeZone than the
+ * DateUtils' API. Caller must specify the locale and timezone.
+ * FORMAT_ABBREV_RELATIVE or FORMAT_ABBREV_ALL can be set in 'flags' to get
+ * the abbreviated forms when available. When 'time' equals to 'now', it
+ * always // returns a string like '0 seconds/minutes/... ago' according to
+ * minResolution.
+ */
+ public static String getRelativeTimeSpanString(Locale locale, java.util.TimeZone tz, long time,
+ long now, long minResolution, int flags) {
+ // Android has been inconsistent about capitalization in the past. e.g. bug http://b/20247811.
+ // Now we capitalize everything consistently.
+ final DisplayContext displayContext = DisplayContext.CAPITALIZATION_FOR_BEGINNING_OF_SENTENCE;
+ return getRelativeTimeSpanString(locale, tz, time, now, minResolution, flags, displayContext);
+ }
+
+ public static String getRelativeTimeSpanString(Locale locale, java.util.TimeZone tz, long time,
+ long now, long minResolution, int flags, DisplayContext displayContext) {
+ if (locale == null) {
+ throw new NullPointerException("locale == null");
+ }
+ if (tz == null) {
+ throw new NullPointerException("tz == null");
+ }
+ ULocale icuLocale = ULocale.forLocale(locale);
+ com.ibm.icu.util.TimeZone icuTimeZone = DateUtilsBridge.icuTimeZone(tz);
+ return getRelativeTimeSpanString(icuLocale, icuTimeZone, time, now, minResolution, flags,
+ displayContext);
+ }
+
+ private static String getRelativeTimeSpanString(ULocale icuLocale,
+ com.ibm.icu.util.TimeZone icuTimeZone, long time, long now, long minResolution, int flags,
+ DisplayContext displayContext) {
+
+ long duration = Math.abs(now - time);
+ boolean past = (now >= time);
+
+ com.ibm.icu.text.RelativeDateTimeFormatter.Style style;
+ if ((flags & (FORMAT_ABBREV_RELATIVE | FORMAT_ABBREV_ALL)) != 0) {
+ style = com.ibm.icu.text.RelativeDateTimeFormatter.Style.SHORT;
+ } else {
+ style = com.ibm.icu.text.RelativeDateTimeFormatter.Style.LONG;
+ }
+
+ com.ibm.icu.text.RelativeDateTimeFormatter.Direction direction;
+ if (past) {
+ direction = com.ibm.icu.text.RelativeDateTimeFormatter.Direction.LAST;
+ } else {
+ direction = com.ibm.icu.text.RelativeDateTimeFormatter.Direction.NEXT;
+ }
+
+ // 'relative' defaults to true as we are generating relative time span
+ // string. It will be set to false when we try to display strings without
+ // a quantity, such as 'Yesterday', etc.
+ boolean relative = true;
+ int count;
+ com.ibm.icu.text.RelativeDateTimeFormatter.RelativeUnit unit;
+ com.ibm.icu.text.RelativeDateTimeFormatter.AbsoluteUnit aunit = null;
+
+ if (duration < MINUTE_IN_MILLIS && minResolution < MINUTE_IN_MILLIS) {
+ count = (int)(duration / SECOND_IN_MILLIS);
+ unit = com.ibm.icu.text.RelativeDateTimeFormatter.RelativeUnit.SECONDS;
+ } else if (duration < HOUR_IN_MILLIS && minResolution < HOUR_IN_MILLIS) {
+ count = (int)(duration / MINUTE_IN_MILLIS);
+ unit = com.ibm.icu.text.RelativeDateTimeFormatter.RelativeUnit.MINUTES;
+ } else if (duration < DAY_IN_MILLIS && minResolution < DAY_IN_MILLIS) {
+ // Even if 'time' actually happened yesterday, we don't format it as
+ // "Yesterday" in this case. Unless the duration is longer than a day,
+ // or minResolution is specified as DAY_IN_MILLIS by user.
+ count = (int)(duration / HOUR_IN_MILLIS);
+ unit = com.ibm.icu.text.RelativeDateTimeFormatter.RelativeUnit.HOURS;
+ } else if (duration < WEEK_IN_MILLIS && minResolution < WEEK_IN_MILLIS) {
+ count = Math.abs(dayDistance(icuTimeZone, time, now));
+ unit = com.ibm.icu.text.RelativeDateTimeFormatter.RelativeUnit.DAYS;
+
+ if (count == 2) {
+ // Some locales have special terms for "2 days ago". Return them if
+ // available. Note that we cannot set up direction and unit here and
+ // make it fall through to use the call near the end of the function,
+ // because for locales that don't have special terms for "2 days ago",
+ // icu4j returns an empty string instead of falling back to strings
+ // like "2 days ago".
+ String str;
+ if (past) {
+ synchronized (CACHED_FORMATTERS) {
+ str = getFormatter(icuLocale, style, displayContext)
+ .format(
+ com.ibm.icu.text.RelativeDateTimeFormatter.Direction.LAST_2,
+ com.ibm.icu.text.RelativeDateTimeFormatter.AbsoluteUnit.DAY);
+ }
+ } else {
+ synchronized (CACHED_FORMATTERS) {
+ str = getFormatter(icuLocale, style, displayContext)
+ .format(
+ com.ibm.icu.text.RelativeDateTimeFormatter.Direction.NEXT_2,
+ com.ibm.icu.text.RelativeDateTimeFormatter.AbsoluteUnit.DAY);
+ }
+ }
+ if (str != null && !str.isEmpty()) {
+ return str;
+ }
+ // Fall back to show something like "2 days ago".
+ } else if (count == 1) {
+ // Show "Yesterday / Tomorrow" instead of "1 day ago / In 1 day".
+ aunit = com.ibm.icu.text.RelativeDateTimeFormatter.AbsoluteUnit.DAY;
+ relative = false;
+ } else if (count == 0) {
+ // Show "Today" if time and now are on the same day.
+ aunit = com.ibm.icu.text.RelativeDateTimeFormatter.AbsoluteUnit.DAY;
+ direction = com.ibm.icu.text.RelativeDateTimeFormatter.Direction.THIS;
+ relative = false;
+ }
+ } else if (minResolution == WEEK_IN_MILLIS) {
+ count = (int)(duration / WEEK_IN_MILLIS);
+ unit = com.ibm.icu.text.RelativeDateTimeFormatter.RelativeUnit.WEEKS;
+ } else {
+ Calendar timeCalendar = DateUtilsBridge.createIcuCalendar(icuTimeZone, icuLocale, time);
+ // The duration is longer than a week and minResolution is not
+ // WEEK_IN_MILLIS. Return the absolute date instead of relative time.
+
+ // Bug 19822016:
+ // If user doesn't supply the year display flag, we need to explicitly
+ // set that to show / hide the year based on time and now. Otherwise
+ // formatDateRange() would determine that based on the current system
+ // time and may give wrong results.
+ if ((flags & (FORMAT_NO_YEAR | FORMAT_SHOW_YEAR)) == 0) {
+ Calendar nowCalendar = DateUtilsBridge.createIcuCalendar(icuTimeZone, icuLocale, now);
+
+ if (timeCalendar.get(Calendar.YEAR) != nowCalendar.get(Calendar.YEAR)) {
+ flags |= FORMAT_SHOW_YEAR;
+ } else {
+ flags |= FORMAT_NO_YEAR;
+ }
+ }
+ return DateTimeFormat.format(icuLocale, timeCalendar, flags, displayContext);
+ }
+
+ synchronized (CACHED_FORMATTERS) {
+ com.ibm.icu.text.RelativeDateTimeFormatter formatter =
+ getFormatter(icuLocale, style, displayContext);
+ if (relative) {
+ return formatter.format(count, direction, unit);
+ } else {
+ return formatter.format(direction, aunit);
+ }
+ }
+ }
+
+ /**
+ * This is the internal API that implements
+ * DateUtils.getRelativeDateTimeString(long, long, long, long, int), which is
+ * to return a string describing 'time' as a time relative to 'now', formatted
+ * like '[relative time/date], [time]'. More examples can be found in
+ * DateUtils' doc.
+ *
+ * The function is similar to getRelativeTimeSpanString, but it always
+ * appends the absolute time to the relative time string to return
+ * '[relative time/date clause], [absolute time clause]'. It also takes an
+ * extra parameter transitionResolution to determine the format of the date
+ * clause. When the elapsed time is less than the transition resolution, it
+ * displays the relative time string. Otherwise, it gives the absolute
+ * numeric date string as the date clause. With the date and time clauses, it
+ * relies on icu4j's RelativeDateTimeFormatter::combineDateAndTime() to
+ * concatenate the two.
+ *
+ * It takes two additional parameters of Locale and TimeZone than the
+ * DateUtils' API. Caller must specify the locale and timezone.
+ * FORMAT_ABBREV_RELATIVE or FORMAT_ABBREV_ALL can be set in 'flags' to get
+ * the abbreviated forms when they are available.
+ *
+ * Bug 5252772: Since the absolute time will always be part of the result,
+ * minResolution will be set to at least DAY_IN_MILLIS to correctly indicate
+ * the date difference. For example, when it's 1:30 AM, it will return
+ * 'Yesterday, 11:30 PM' for getRelativeDateTimeString(null, null,
+ * now - 2 hours, now, HOUR_IN_MILLIS, DAY_IN_MILLIS, 0), instead of '2
+ * hours ago, 11:30 PM' even with minResolution being HOUR_IN_MILLIS.
+ */
+ public static String getRelativeDateTimeString(Locale locale, java.util.TimeZone tz, long time,
+ long now, long minResolution, long transitionResolution, int flags) {
+
+ if (locale == null) {
+ throw new NullPointerException("locale == null");
+ }
+ if (tz == null) {
+ throw new NullPointerException("tz == null");
+ }
+ ULocale icuLocale = ULocale.forLocale(locale);
+ com.ibm.icu.util.TimeZone icuTimeZone = DateUtilsBridge.icuTimeZone(tz);
+
+ long duration = Math.abs(now - time);
+ // It doesn't make much sense to have results like: "1 week ago, 10:50 AM".
+ if (transitionResolution > WEEK_IN_MILLIS) {
+ transitionResolution = WEEK_IN_MILLIS;
+ }
+ com.ibm.icu.text.RelativeDateTimeFormatter.Style style;
+ if ((flags & (FORMAT_ABBREV_RELATIVE | FORMAT_ABBREV_ALL)) != 0) {
+ style = com.ibm.icu.text.RelativeDateTimeFormatter.Style.SHORT;
+ } else {
+ style = com.ibm.icu.text.RelativeDateTimeFormatter.Style.LONG;
+ }
+
+ Calendar timeCalendar = DateUtilsBridge.createIcuCalendar(icuTimeZone, icuLocale, time);
+ Calendar nowCalendar = DateUtilsBridge.createIcuCalendar(icuTimeZone, icuLocale, now);
+
+ int days = Math.abs(DateUtilsBridge.dayDistance(timeCalendar, nowCalendar));
+
+ // Now get the date clause, either in relative format or the actual date.
+ String dateClause;
+ if (duration < transitionResolution) {
+ // This is to fix bug 5252772. If there is any date difference, we should
+ // promote the minResolution to DAY_IN_MILLIS so that it can display the
+ // date instead of "x hours/minutes ago, [time]".
+ if (days > 0 && minResolution < DAY_IN_MILLIS) {
+ minResolution = DAY_IN_MILLIS;
+ }
+ dateClause = getRelativeTimeSpanString(icuLocale, icuTimeZone, time, now, minResolution,
+ flags, DisplayContext.CAPITALIZATION_FOR_BEGINNING_OF_SENTENCE);
+ } else {
+ // We always use fixed flags to format the date clause. User-supplied
+ // flags are ignored.
+ if (timeCalendar.get(Calendar.YEAR) != nowCalendar.get(Calendar.YEAR)) {
+ // Different years
+ flags = FORMAT_SHOW_DATE | FORMAT_SHOW_YEAR | FORMAT_NUMERIC_DATE;
+ } else {
+ // Default
+ flags = FORMAT_SHOW_DATE | FORMAT_NO_YEAR | FORMAT_ABBREV_MONTH;
+ }
+
+ dateClause = DateTimeFormat.format(icuLocale, timeCalendar, flags,
+ DisplayContext.CAPITALIZATION_FOR_BEGINNING_OF_SENTENCE);
+ }
+
+ String timeClause = DateTimeFormat.format(icuLocale, timeCalendar, FORMAT_SHOW_TIME,
+ DisplayContext.CAPITALIZATION_NONE);
+
+ // icu4j also has other options available to control the capitalization. We are currently using
+ // the _NONE option only.
+ DisplayContext capitalizationContext = DisplayContext.CAPITALIZATION_NONE;
+
+ // Combine the two clauses, such as '5 days ago, 10:50 AM'.
+ synchronized (CACHED_FORMATTERS) {
+ return getFormatter(icuLocale, style, capitalizationContext)
+ .combineDateAndTime(dateClause, timeClause);
+ }
+ }
+
+ /**
+ * getFormatter() caches the RelativeDateTimeFormatter instances based on
+ * the combination of localeName, sytle and capitalizationContext. It
+ * should always be used along with the action of the formatter in a
+ * synchronized block, because otherwise the formatter returned by
+ * getFormatter() may have been evicted by the time of the call to
+ * formatter->action().
+ */
+ private static com.ibm.icu.text.RelativeDateTimeFormatter getFormatter(
+ ULocale locale, com.ibm.icu.text.RelativeDateTimeFormatter.Style style,
+ DisplayContext displayContext) {
+ String key = locale + "\t" + style + "\t" + displayContext;
+ com.ibm.icu.text.RelativeDateTimeFormatter formatter = CACHED_FORMATTERS.get(key);
+ if (formatter == null) {
+ formatter = com.ibm.icu.text.RelativeDateTimeFormatter.getInstance(
+ locale, null, style, displayContext);
+ CACHED_FORMATTERS.put(key, formatter);
+ }
+ return formatter;
+ }
+
+ // Return the date difference for the two times in a given timezone.
+ private static int dayDistance(com.ibm.icu.util.TimeZone icuTimeZone, long startTime,
+ long endTime) {
+ return julianDay(icuTimeZone, endTime) - julianDay(icuTimeZone, startTime);
+ }
+
+ private static int julianDay(com.ibm.icu.util.TimeZone icuTimeZone, long time) {
+ long utcMs = time + icuTimeZone.getOffset(time);
+ return (int) (utcMs / DAY_IN_MS) + EPOCH_JULIAN_DAY;
+ }
+}
diff --git a/luni/src/main/java/libcore/io/BlockGuardOs.java b/luni/src/main/java/libcore/io/BlockGuardOs.java
index b3dc74b..532493a 100644
--- a/luni/src/main/java/libcore/io/BlockGuardOs.java
+++ b/luni/src/main/java/libcore/io/BlockGuardOs.java
@@ -83,7 +83,7 @@ public class BlockGuardOs extends ForwardingOs {
// The usual case is that this _isn't_ a socket, so the getsockopt(2) call in
// isLingerSocket will throw, and that's really expensive. Try to avoid asking
// if we don't care.
- if (fd.isSocket()) {
+ if (fd.isSocket$()) {
if (isLingerSocket(fd)) {
// If the fd is a socket with SO_LINGER set, we might block indefinitely.
// We allow non-linger sockets so that apps can close their network
diff --git a/luni/src/main/java/libcore/io/ForwardingOs.java b/luni/src/main/java/libcore/io/ForwardingOs.java
index 584fd58..cb77573 100644
--- a/luni/src/main/java/libcore/io/ForwardingOs.java
+++ b/luni/src/main/java/libcore/io/ForwardingOs.java
@@ -54,10 +54,12 @@ public class ForwardingOs implements Os {
public boolean access(String path, int mode) throws ErrnoException { return os.access(path, mode); }
public InetAddress[] android_getaddrinfo(String node, StructAddrinfo hints, int netId) throws GaiException { return os.android_getaddrinfo(node, hints, netId); }
public void bind(FileDescriptor fd, InetAddress address, int port) throws ErrnoException, SocketException { os.bind(fd, address, port); }
+ public void bind(FileDescriptor fd, SocketAddress address) throws ErrnoException, SocketException { os.bind(fd, address); }
public void chmod(String path, int mode) throws ErrnoException { os.chmod(path, mode); }
public void chown(String path, int uid, int gid) throws ErrnoException { os.chown(path, uid, gid); }
public void close(FileDescriptor fd) throws ErrnoException { os.close(fd); }
public void connect(FileDescriptor fd, InetAddress address, int port) throws ErrnoException, SocketException { os.connect(fd, address, port); }
+ public void connect(FileDescriptor fd, SocketAddress address) throws ErrnoException, SocketException { os.connect(fd, address); }
public FileDescriptor dup(FileDescriptor oldFd) throws ErrnoException { return os.dup(oldFd); }
public FileDescriptor dup2(FileDescriptor oldFd, int newFd) throws ErrnoException { return os.dup2(oldFd, newFd); }
public String[] environ() { return os.environ(); }
@@ -65,9 +67,9 @@ public class ForwardingOs implements Os {
public void execve(String filename, String[] argv, String[] envp) throws ErrnoException { os.execve(filename, argv, envp); }
public void fchmod(FileDescriptor fd, int mode) throws ErrnoException { os.fchmod(fd, mode); }
public void fchown(FileDescriptor fd, int uid, int gid) throws ErrnoException { os.fchown(fd, uid, gid); }
- public int fcntlVoid(FileDescriptor fd, int cmd) throws ErrnoException { return os.fcntlVoid(fd, cmd); }
- public int fcntlLong(FileDescriptor fd, int cmd, long arg) throws ErrnoException { return os.fcntlLong(fd, cmd, arg); }
public int fcntlFlock(FileDescriptor fd, int cmd, StructFlock arg) throws ErrnoException, InterruptedIOException { return os.fcntlFlock(fd, cmd, arg); }
+ public int fcntlInt(FileDescriptor fd, int cmd, int arg) throws ErrnoException { return os.fcntlInt(fd, cmd, arg); }
+ public int fcntlVoid(FileDescriptor fd, int cmd) throws ErrnoException { return os.fcntlVoid(fd, cmd); }
public void fdatasync(FileDescriptor fd) throws ErrnoException { os.fdatasync(fd); }
public StructStat fstat(FileDescriptor fd) throws ErrnoException { return os.fstat(fd); }
public StructStatVfs fstatvfs(FileDescriptor fd) throws ErrnoException { return os.fstatvfs(fd); }
@@ -80,6 +82,7 @@ public class ForwardingOs implements Os {
public String getenv(String name) { return os.getenv(name); }
public String getnameinfo(InetAddress address, int flags) throws GaiException { return os.getnameinfo(address, flags); }
public SocketAddress getpeername(FileDescriptor fd) throws ErrnoException { return os.getpeername(fd); }
+ public int getpgid(int pid) throws ErrnoException { return os.getpgid(pid); }
public int getpid() { return os.getpid(); }
public int getppid() { return os.getppid(); }
public StructPasswd getpwnam(String name) throws ErrnoException { return os.getpwnam(name); }
@@ -93,6 +96,7 @@ public class ForwardingOs implements Os {
public StructUcred getsockoptUcred(FileDescriptor fd, int level, int option) throws ErrnoException { return os.getsockoptUcred(fd, level, option); }
public int gettid() { return os.gettid(); }
public int getuid() { return os.getuid(); }
+ public int getxattr(String path, String name, byte[] outValue) throws ErrnoException { return os.getxattr(path, name, outValue); }
public String if_indextoname(int index) { return os.if_indextoname(index); }
public InetAddress inet_pton(int family, String address) { return os.inet_pton(family, address); }
public InetAddress ioctlInetAddress(FileDescriptor fd, int cmd, String interfaceName) throws ErrnoException { return os.ioctlInetAddress(fd, cmd, interfaceName); }
@@ -113,7 +117,7 @@ public class ForwardingOs implements Os {
public void munlock(long address, long byteCount) throws ErrnoException { os.munlock(address, byteCount); }
public void munmap(long address, long byteCount) throws ErrnoException { os.munmap(address, byteCount); }
public FileDescriptor open(String path, int flags, int mode) throws ErrnoException { return os.open(path, flags, mode); }
- public FileDescriptor[] pipe() throws ErrnoException { return os.pipe(); }
+ public FileDescriptor[] pipe2(int flags) throws ErrnoException { return os.pipe2(flags); }
public int poll(StructPollfd[] fds, int timeoutMs) throws ErrnoException { return os.poll(fds, timeoutMs); }
public void posix_fallocate(FileDescriptor fd, long offset, long length) throws ErrnoException { os.posix_fallocate(fd, offset, length); }
public int prctl(int option, long arg2, long arg3, long arg4, long arg5) throws ErrnoException { return os.prctl(option, arg2, arg3, arg4, arg5); };
@@ -128,14 +132,19 @@ public class ForwardingOs implements Os {
public int recvfrom(FileDescriptor fd, ByteBuffer buffer, int flags, InetSocketAddress srcAddress) throws ErrnoException, SocketException { return os.recvfrom(fd, buffer, flags, srcAddress); }
public int recvfrom(FileDescriptor fd, byte[] bytes, int byteOffset, int byteCount, int flags, InetSocketAddress srcAddress) throws ErrnoException, SocketException { return os.recvfrom(fd, bytes, byteOffset, byteCount, flags, srcAddress); }
public void remove(String path) throws ErrnoException { os.remove(path); }
+ public void removexattr(String path, String name) throws ErrnoException { os.removexattr(path, name); }
public void rename(String oldPath, String newPath) throws ErrnoException { os.rename(oldPath, newPath); }
public long sendfile(FileDescriptor outFd, FileDescriptor inFd, MutableLong inOffset, long byteCount) throws ErrnoException { return os.sendfile(outFd, inFd, inOffset, byteCount); }
public int sendto(FileDescriptor fd, ByteBuffer buffer, int flags, InetAddress inetAddress, int port) throws ErrnoException, SocketException { return os.sendto(fd, buffer, flags, inetAddress, port); }
public int sendto(FileDescriptor fd, byte[] bytes, int byteOffset, int byteCount, int flags, InetAddress inetAddress, int port) throws ErrnoException, SocketException { return os.sendto(fd, bytes, byteOffset, byteCount, flags, inetAddress, port); }
+ public int sendto(FileDescriptor fd, byte[] bytes, int byteOffset, int byteCount, int flags, SocketAddress address) throws ErrnoException, SocketException { return os.sendto(fd, bytes, byteOffset, byteCount, flags, address); }
public void setegid(int egid) throws ErrnoException { os.setegid(egid); }
public void setenv(String name, String value, boolean overwrite) throws ErrnoException { os.setenv(name, value, overwrite); }
public void seteuid(int euid) throws ErrnoException { os.seteuid(euid); }
public void setgid(int gid) throws ErrnoException { os.setgid(gid); }
+ public void setpgid(int pid, int pgid) throws ErrnoException { os.setpgid(pid, pgid); }
+ public void setregid(int rgid, int egid) throws ErrnoException { os.setregid(rgid, egid); }
+ public void setreuid(int ruid, int euid) throws ErrnoException { os.setregid(ruid, euid); }
public int setsid() throws ErrnoException { return os.setsid(); }
public void setsockoptByte(FileDescriptor fd, int level, int option, int value) throws ErrnoException { os.setsockoptByte(fd, level, option, value); }
public void setsockoptIfreq(FileDescriptor fd, int level, int option, String value) throws ErrnoException { os.setsockoptIfreq(fd, level, option, value); }
@@ -146,6 +155,7 @@ public class ForwardingOs implements Os {
public void setsockoptLinger(FileDescriptor fd, int level, int option, StructLinger value) throws ErrnoException { os.setsockoptLinger(fd, level, option, value); }
public void setsockoptTimeval(FileDescriptor fd, int level, int option, StructTimeval value) throws ErrnoException { os.setsockoptTimeval(fd, level, option, value); }
public void setuid(int uid) throws ErrnoException { os.setuid(uid); }
+ public void setxattr(String path, String name, byte[] value, int flags) throws ErrnoException { os.setxattr(path, name, value, flags); }
public void shutdown(FileDescriptor fd, int how) throws ErrnoException { os.shutdown(fd, how); }
public FileDescriptor socket(int domain, int type, int protocol) throws ErrnoException { return os.socket(domain, type, protocol); }
public void socketpair(int domain, int type, int protocol, FileDescriptor fd1, FileDescriptor fd2) throws ErrnoException { os.socketpair(domain, type, protocol, fd1, fd2); }
diff --git a/luni/src/main/java/libcore/io/IoBridge.java b/luni/src/main/java/libcore/io/IoBridge.java
index acc8d4f..fcb30dd 100644
--- a/luni/src/main/java/libcore/io/IoBridge.java
+++ b/luni/src/main/java/libcore/io/IoBridge.java
@@ -225,11 +225,7 @@ public final class IoBridge {
if (!fd.valid()) {
throw new SocketException("Socket closed");
}
- if (errnoException.errno == EINTR) {
- return false; // Punt and ask the caller to try again.
- } else {
- cause = errnoException;
- }
+ cause = errnoException;
}
String detail = connectDetail(inetAddress, port, timeoutMs, cause);
if (cause.errno == ETIMEDOUT) {
diff --git a/luni/src/main/java/libcore/io/IoUtils.java b/luni/src/main/java/libcore/io/IoUtils.java
index 5a19f17..b01759d 100644
--- a/luni/src/main/java/libcore/io/IoUtils.java
+++ b/luni/src/main/java/libcore/io/IoUtils.java
@@ -30,8 +30,6 @@ import java.util.Random;
import static android.system.OsConstants.*;
public final class IoUtils {
- private static final Random TEMPORARY_DIRECTORY_PRNG = new Random();
-
private IoUtils() {
}
@@ -96,7 +94,7 @@ public final class IoUtils {
} else {
flags &= ~O_NONBLOCK;
}
- Libcore.os.fcntlLong(fd, F_SETFL, flags);
+ Libcore.os.fcntlInt(fd, F_SETFL, flags);
} catch (ErrnoException errnoException) {
throw errnoException.rethrowAsIOException();
}
@@ -142,7 +140,7 @@ public final class IoUtils {
*/
public static File createTemporaryDirectory(String prefix) {
while (true) {
- String candidateName = prefix + TEMPORARY_DIRECTORY_PRNG.nextInt();
+ String candidateName = prefix + Math.randomIntInternal();
File result = new File(System.getProperty("java.io.tmpdir"), candidateName);
if (result.mkdir()) {
return result;
diff --git a/luni/src/main/java/libcore/io/Os.java b/luni/src/main/java/libcore/io/Os.java
index 9f080a6..6d28b95 100644
--- a/luni/src/main/java/libcore/io/Os.java
+++ b/luni/src/main/java/libcore/io/Os.java
@@ -45,10 +45,12 @@ public interface Os {
public boolean access(String path, int mode) throws ErrnoException;
public InetAddress[] android_getaddrinfo(String node, StructAddrinfo hints, int netId) throws GaiException;
public void bind(FileDescriptor fd, InetAddress address, int port) throws ErrnoException, SocketException;
+ public void bind(FileDescriptor fd, SocketAddress address) throws ErrnoException, SocketException;
public void chmod(String path, int mode) throws ErrnoException;
public void chown(String path, int uid, int gid) throws ErrnoException;
public void close(FileDescriptor fd) throws ErrnoException;
public void connect(FileDescriptor fd, InetAddress address, int port) throws ErrnoException, SocketException;
+ public void connect(FileDescriptor fd, SocketAddress address) throws ErrnoException, SocketException;
public FileDescriptor dup(FileDescriptor oldFd) throws ErrnoException;
public FileDescriptor dup2(FileDescriptor oldFd, int newFd) throws ErrnoException;
public String[] environ();
@@ -56,9 +58,9 @@ public interface Os {
public void execve(String filename, String[] argv, String[] envp) throws ErrnoException;
public void fchmod(FileDescriptor fd, int mode) throws ErrnoException;
public void fchown(FileDescriptor fd, int uid, int gid) throws ErrnoException;
- public int fcntlVoid(FileDescriptor fd, int cmd) throws ErrnoException;
- public int fcntlLong(FileDescriptor fd, int cmd, long arg) throws ErrnoException;
public int fcntlFlock(FileDescriptor fd, int cmd, StructFlock arg) throws ErrnoException, InterruptedIOException;
+ public int fcntlInt(FileDescriptor fd, int cmd, int arg) throws ErrnoException;
+ public int fcntlVoid(FileDescriptor fd, int cmd) throws ErrnoException;
public void fdatasync(FileDescriptor fd) throws ErrnoException;
public StructStat fstat(FileDescriptor fd) throws ErrnoException;
public StructStatVfs fstatvfs(FileDescriptor fd) throws ErrnoException;
@@ -72,6 +74,7 @@ public interface Os {
/* TODO: break into getnameinfoHost and getnameinfoService? */
public String getnameinfo(InetAddress address, int flags) throws GaiException;
public SocketAddress getpeername(FileDescriptor fd) throws ErrnoException;
+ public int getpgid(int pid) throws ErrnoException;
public int getpid();
public int getppid();
public StructPasswd getpwnam(String name) throws ErrnoException;
@@ -85,6 +88,7 @@ public interface Os {
public StructUcred getsockoptUcred(FileDescriptor fd, int level, int option) throws ErrnoException;
public int gettid();
public int getuid();
+ public int getxattr(String path, String name, byte[] outValue) throws ErrnoException;
public String if_indextoname(int index);
public InetAddress inet_pton(int family, String address);
public InetAddress ioctlInetAddress(FileDescriptor fd, int cmd, String interfaceName) throws ErrnoException;
@@ -105,7 +109,7 @@ public interface Os {
public void munlock(long address, long byteCount) throws ErrnoException;
public void munmap(long address, long byteCount) throws ErrnoException;
public FileDescriptor open(String path, int flags, int mode) throws ErrnoException;
- public FileDescriptor[] pipe() throws ErrnoException;
+ public FileDescriptor[] pipe2(int flags) throws ErrnoException;
/* TODO: if we used the non-standard ppoll(2) behind the scenes, we could take a long timeout. */
public int poll(StructPollfd[] fds, int timeoutMs) throws ErrnoException;
public void posix_fallocate(FileDescriptor fd, long offset, long length) throws ErrnoException;
@@ -121,14 +125,19 @@ public interface Os {
public int recvfrom(FileDescriptor fd, ByteBuffer buffer, int flags, InetSocketAddress srcAddress) throws ErrnoException, SocketException;
public int recvfrom(FileDescriptor fd, byte[] bytes, int byteOffset, int byteCount, int flags, InetSocketAddress srcAddress) throws ErrnoException, SocketException;
public void remove(String path) throws ErrnoException;
+ public void removexattr(String path, String name) throws ErrnoException;
public void rename(String oldPath, String newPath) throws ErrnoException;
public int sendto(FileDescriptor fd, ByteBuffer buffer, int flags, InetAddress inetAddress, int port) throws ErrnoException, SocketException;
public int sendto(FileDescriptor fd, byte[] bytes, int byteOffset, int byteCount, int flags, InetAddress inetAddress, int port) throws ErrnoException, SocketException;
+ public int sendto(FileDescriptor fd, byte[] bytes, int byteOffset, int byteCount, int flags, SocketAddress address) throws ErrnoException, SocketException;
public long sendfile(FileDescriptor outFd, FileDescriptor inFd, MutableLong inOffset, long byteCount) throws ErrnoException;
public void setegid(int egid) throws ErrnoException;
public void setenv(String name, String value, boolean overwrite) throws ErrnoException;
public void seteuid(int euid) throws ErrnoException;
public void setgid(int gid) throws ErrnoException;
+ public void setpgid(int pid, int pgid) throws ErrnoException;
+ public void setregid(int rgid, int egid) throws ErrnoException;
+ public void setreuid(int ruid, int euid) throws ErrnoException;
public int setsid() throws ErrnoException;
public void setsockoptByte(FileDescriptor fd, int level, int option, int value) throws ErrnoException;
public void setsockoptIfreq(FileDescriptor fd, int level, int option, String value) throws ErrnoException;
@@ -139,6 +148,7 @@ public interface Os {
public void setsockoptLinger(FileDescriptor fd, int level, int option, StructLinger value) throws ErrnoException;
public void setsockoptTimeval(FileDescriptor fd, int level, int option, StructTimeval value) throws ErrnoException;
public void setuid(int uid) throws ErrnoException;
+ public void setxattr(String path, String name, byte[] value, int flags) throws ErrnoException;
public void shutdown(FileDescriptor fd, int how) throws ErrnoException;
public FileDescriptor socket(int domain, int type, int protocol) throws ErrnoException;
public void socketpair(int domain, int type, int protocol, FileDescriptor fd1, FileDescriptor fd2) throws ErrnoException;
diff --git a/luni/src/main/java/libcore/io/Posix.java b/luni/src/main/java/libcore/io/Posix.java
index 5bd1b06..151809d 100644
--- a/luni/src/main/java/libcore/io/Posix.java
+++ b/luni/src/main/java/libcore/io/Posix.java
@@ -48,10 +48,12 @@ public final class Posix implements Os {
public native boolean access(String path, int mode) throws ErrnoException;
public native InetAddress[] android_getaddrinfo(String node, StructAddrinfo hints, int netId) throws GaiException;
public native void bind(FileDescriptor fd, InetAddress address, int port) throws ErrnoException, SocketException;
+ public native void bind(FileDescriptor fd, SocketAddress address) throws ErrnoException, SocketException;
public native void chmod(String path, int mode) throws ErrnoException;
public native void chown(String path, int uid, int gid) throws ErrnoException;
public native void close(FileDescriptor fd) throws ErrnoException;
public native void connect(FileDescriptor fd, InetAddress address, int port) throws ErrnoException, SocketException;
+ public native void connect(FileDescriptor fd, SocketAddress address) throws ErrnoException, SocketException;
public native FileDescriptor dup(FileDescriptor oldFd) throws ErrnoException;
public native FileDescriptor dup2(FileDescriptor oldFd, int newFd) throws ErrnoException;
public native String[] environ();
@@ -59,9 +61,9 @@ public final class Posix implements Os {
public native void execve(String filename, String[] argv, String[] envp) throws ErrnoException;
public native void fchmod(FileDescriptor fd, int mode) throws ErrnoException;
public native void fchown(FileDescriptor fd, int uid, int gid) throws ErrnoException;
- public native int fcntlVoid(FileDescriptor fd, int cmd) throws ErrnoException;
- public native int fcntlLong(FileDescriptor fd, int cmd, long arg) throws ErrnoException;
public native int fcntlFlock(FileDescriptor fd, int cmd, StructFlock arg) throws ErrnoException, InterruptedIOException;
+ public native int fcntlInt(FileDescriptor fd, int cmd, int arg) throws ErrnoException;
+ public native int fcntlVoid(FileDescriptor fd, int cmd) throws ErrnoException;
public native void fdatasync(FileDescriptor fd) throws ErrnoException;
public native StructStat fstat(FileDescriptor fd) throws ErrnoException;
public native StructStatVfs fstatvfs(FileDescriptor fd) throws ErrnoException;
@@ -74,6 +76,7 @@ public final class Posix implements Os {
public native String getenv(String name);
public native String getnameinfo(InetAddress address, int flags) throws GaiException;
public native SocketAddress getpeername(FileDescriptor fd) throws ErrnoException;
+ public native int getpgid(int pid);
public native int getpid();
public native int getppid();
public native StructPasswd getpwnam(String name) throws ErrnoException;
@@ -87,6 +90,7 @@ public final class Posix implements Os {
public native StructUcred getsockoptUcred(FileDescriptor fd, int level, int option) throws ErrnoException;
public native int gettid();
public native int getuid();
+ public native int getxattr(String path, String name, byte[] outValue) throws ErrnoException;
public native String if_indextoname(int index);
public native InetAddress inet_pton(int family, String address);
public native InetAddress ioctlInetAddress(FileDescriptor fd, int cmd, String interfaceName) throws ErrnoException;
@@ -107,7 +111,7 @@ public final class Posix implements Os {
public native void munlock(long address, long byteCount) throws ErrnoException;
public native void munmap(long address, long byteCount) throws ErrnoException;
public native FileDescriptor open(String path, int flags, int mode) throws ErrnoException;
- public native FileDescriptor[] pipe() throws ErrnoException;
+ public native FileDescriptor[] pipe2(int flags) throws ErrnoException;
public native int poll(StructPollfd[] fds, int timeoutMs) throws ErrnoException;
public native void posix_fallocate(FileDescriptor fd, long offset, long length) throws ErrnoException;
public native int prctl(int option, long arg2, long arg3, long arg4, long arg5) throws ErrnoException;
@@ -186,6 +190,7 @@ public final class Posix implements Os {
}
private native int recvfromBytes(FileDescriptor fd, Object buffer, int byteOffset, int byteCount, int flags, InetSocketAddress srcAddress) throws ErrnoException, SocketException;
public native void remove(String path) throws ErrnoException;
+ public native void removexattr(String path, String name) throws ErrnoException;
public native void rename(String oldPath, String newPath) throws ErrnoException;
public native long sendfile(FileDescriptor outFd, FileDescriptor inFd, MutableLong inOffset, long byteCount) throws ErrnoException;
public int sendto(FileDescriptor fd, ByteBuffer buffer, int flags, InetAddress inetAddress, int port) throws ErrnoException, SocketException {
@@ -205,11 +210,18 @@ public final class Posix implements Os {
// This indirection isn't strictly necessary, but ensures that our public interface is type safe.
return sendtoBytes(fd, bytes, byteOffset, byteCount, flags, inetAddress, port);
}
+ public int sendto(FileDescriptor fd, byte[] bytes, int byteOffset, int byteCount, int flags, SocketAddress address) throws ErrnoException, SocketException {
+ return sendtoBytes(fd, bytes, byteOffset, byteCount, flags, address);
+ }
private native int sendtoBytes(FileDescriptor fd, Object buffer, int byteOffset, int byteCount, int flags, InetAddress inetAddress, int port) throws ErrnoException, SocketException;
+ private native int sendtoBytes(FileDescriptor fd, Object buffer, int byteOffset, int byteCount, int flags, SocketAddress address) throws ErrnoException, SocketException;
public native void setegid(int egid) throws ErrnoException;
public native void setenv(String name, String value, boolean overwrite) throws ErrnoException;
public native void seteuid(int euid) throws ErrnoException;
public native void setgid(int gid) throws ErrnoException;
+ public native void setpgid(int pid, int pgid) throws ErrnoException;
+ public native void setregid(int rgid, int egid) throws ErrnoException;
+ public native void setreuid(int ruid, int euid) throws ErrnoException;
public native int setsid() throws ErrnoException;
public native void setsockoptByte(FileDescriptor fd, int level, int option, int value) throws ErrnoException;
public native void setsockoptIfreq(FileDescriptor fd, int level, int option, String value) throws ErrnoException;
@@ -220,6 +232,7 @@ public final class Posix implements Os {
public native void setsockoptLinger(FileDescriptor fd, int level, int option, StructLinger value) throws ErrnoException;
public native void setsockoptTimeval(FileDescriptor fd, int level, int option, StructTimeval value) throws ErrnoException;
public native void setuid(int uid) throws ErrnoException;
+ public native void setxattr(String path, String name, byte[] value, int flags) throws ErrnoException;
public native void shutdown(FileDescriptor fd, int how) throws ErrnoException;
public native FileDescriptor socket(int domain, int type, int protocol) throws ErrnoException;
public native void socketpair(int domain, int type, int protocol, FileDescriptor fd1, FileDescriptor fd2) throws ErrnoException;
diff --git a/luni/src/main/java/libcore/net/MimeUtils.java b/luni/src/main/java/libcore/net/MimeUtils.java
index 125ea87..e36b3d1 100644
--- a/luni/src/main/java/libcore/net/MimeUtils.java
+++ b/luni/src/main/java/libcore/net/MimeUtils.java
@@ -16,13 +16,8 @@
package libcore.net;
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.IOException;
-import java.io.InputStream;
import java.util.HashMap;
import java.util.Map;
-import java.util.Properties;
/**
* Utilities for dealing with MIME types.
@@ -49,6 +44,7 @@ public final class MimeUtils {
add("application/andrew-inset", "ez");
add("application/dsptype", "tsp");
+ add("application/epub+zip", "epub");
add("application/hta", "hta");
add("application/mac-binhex40", "hqx");
add("application/mathematica", "nb");
@@ -73,6 +69,8 @@ public final class MimeUtils {
add("application/vnd.oasis.opendocument.graphics", "odg");
add("application/vnd.oasis.opendocument.graphics-template", "otg");
add("application/vnd.oasis.opendocument.image", "odi");
+ add("application/vnd.oasis.opendocument.presentation", "odp");
+ add("application/vnd.oasis.opendocument.presentation-template", "otp");
add("application/vnd.oasis.opendocument.spreadsheet", "ods");
add("application/vnd.oasis.opendocument.spreadsheet-template", "ots");
add("application/vnd.oasis.opendocument.text", "odt");
@@ -148,6 +146,7 @@ public final class MimeUtils {
add("application/x-gtar", "gtar");
add("application/x-gtar", "taz");
add("application/x-hdf", "hdf");
+ add("application/x-hwp", "hwp"); // http://b/18788282.
add("application/x-ica", "ica");
add("application/x-internet-signup", "ins");
add("application/x-internet-signup", "isp");
@@ -378,7 +377,6 @@ public final class MimeUtils {
add("video/x-webex", "wrf");
add("x-conference/x-cooltalk", "ice");
add("x-epoc/x-sisx-app", "sisx");
- applyOverrides();
}
private static void add(String mimeType, String extension) {
@@ -395,61 +393,6 @@ public final class MimeUtils {
}
}
- private static InputStream getContentTypesPropertiesStream() {
- // User override?
- String userTable = System.getProperty("content.types.user.table");
- if (userTable != null) {
- File f = new File(userTable);
- if (f.exists()) {
- try {
- return new FileInputStream(f);
- } catch (IOException ignored) {
- }
- }
- }
-
- // Standard location?
- File f = new File(System.getProperty("java.home"), "lib" + File.separator + "content-types.properties");
- if (f.exists()) {
- try {
- return new FileInputStream(f);
- } catch (IOException ignored) {
- }
- }
-
- return null;
- }
-
- /**
- * This isn't what the RI does. The RI doesn't have hard-coded defaults, so supplying your
- * own "content.types.user.table" means you don't get any of the built-ins, and the built-ins
- * come from "$JAVA_HOME/lib/content-types.properties".
- */
- private static void applyOverrides() {
- // Get the appropriate InputStream to read overrides from, if any.
- InputStream stream = getContentTypesPropertiesStream();
- if (stream == null) {
- return;
- }
-
- try {
- try {
- // Read the properties file...
- Properties overrides = new Properties();
- overrides.load(stream);
- // And translate its mapping to ours...
- for (Map.Entry<Object, Object> entry : overrides.entrySet()) {
- String extension = (String) entry.getKey();
- String mimeType = (String) entry.getValue();
- add(mimeType, extension);
- }
- } finally {
- stream.close();
- }
- } catch (IOException ignored) {
- }
- }
-
private MimeUtils() {
}
diff --git a/luni/src/main/java/libcore/net/NetworkSecurityPolicy.java b/luni/src/main/java/libcore/net/NetworkSecurityPolicy.java
new file mode 100644
index 0000000..b1a41e8
--- /dev/null
+++ b/luni/src/main/java/libcore/net/NetworkSecurityPolicy.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package libcore.net;
+
+import libcore.net.url.FtpURLConnection;
+
+/**
+ * Network security policy for this process/application.
+ *
+ * <p>Network stacks/components are expected to honor this policy. Components which can use the
+ * Android framework API should be accessing this policy via the framework's
+ * {@code android.security.NetworkSecurityPolicy} instead of via this class.
+ *
+ * <p>The policy currently consists of a single flag: whether cleartext network traffic is
+ * permitted. See {@link #isCleartextTrafficPermitted()}.
+ */
+public class NetworkSecurityPolicy {
+
+ private static volatile boolean cleartextTrafficPermitted = true;
+
+ /**
+ * Returns whether cleartext network traffic (e.g. HTTP, FTP, XMPP, IMAP, SMTP -- without TLS or
+ * STARTTLS) is permitted for this process.
+ *
+ * <p>When cleartext network traffic is not permitted, the platform's components (e.g. HTTP
+ * stacks, {@code WebView}, {@code MediaPlayer}) will refuse this process's requests to use
+ * cleartext traffic. Third-party libraries are encouraged to do the same.
+ *
+ * <p>This flag is honored on a best effort basis because it's impossible to prevent all
+ * cleartext traffic from an application given the level of access provided to applications on
+ * Android. For example, there's no expectation that {@link java.net.Socket} API will honor this
+ * flag. Luckily, most network traffic from apps is handled by higher-level network stacks which
+ * can be made to honor this flag. Platform-provided network stacks (e.g. HTTP and FTP) honor
+ * this flag from day one, and well-established third-party network stacks will eventually
+ * honor it.
+ *
+ * <p>See {@link FtpURLConnection} for an example of honoring this flag.
+ */
+ public static boolean isCleartextTrafficPermitted() {
+ return cleartextTrafficPermitted;
+ }
+
+ /**
+ * Sets whether cleartext network traffic (e.g. HTTP, FTP, XMPP, IMAP, SMTP -- without TLS or
+ * STARTTLS) is permitted for this process.
+ *
+ * @see #isCleartextTrafficPermitted()
+ */
+ public static void setCleartextTrafficPermitted(boolean permitted) {
+ cleartextTrafficPermitted = permitted;
+ }
+}
diff --git a/luni/src/main/java/libcore/net/http/ResponseUtils.java b/luni/src/main/java/libcore/net/http/ResponseUtils.java
new file mode 100644
index 0000000..c892b53
--- /dev/null
+++ b/luni/src/main/java/libcore/net/http/ResponseUtils.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package libcore.net.http;
+
+import java.nio.charset.Charset;
+import java.nio.charset.IllegalCharsetNameException;
+import java.nio.charset.StandardCharsets;
+import java.nio.charset.UnsupportedCharsetException;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * @hide
+ */
+public class ResponseUtils {
+ /**
+ * Returns the response charset of a HTTP response based on the {@code Content-Type} of
+ * the response (see RFC 7230). If the {@code Content-Type} header is missing or invalid,
+ * the response is assumed to be encoded as {@code UTF-8}. Note that a charset usually
+ * makes sense only for {@code "text/plain"} and other "text based" responses.
+ *
+ * @throws IllegalCharsetNameException if the response specified charset is illegal.
+ * @throws UnsupportedCharsetException if the response specified charset is unsupported.
+ */
+ public static Charset responseCharset(String contentTypeHeader)
+ throws IllegalCharsetNameException, UnsupportedCharsetException {
+ Charset responseCharset = StandardCharsets.UTF_8;
+ if (contentTypeHeader != null) {
+ Map<String, String> contentTypeParams = parseContentTypeParameters(contentTypeHeader);
+ String charsetParameter = contentTypeParams.get("charset");
+ if (charsetParameter != null) {
+ responseCharset = Charset.forName(charsetParameter);
+ }
+ }
+
+ return responseCharset;
+ }
+
+ /**
+ * Parse content-type parameters. The format of this header is roughly :
+ * {@code type/subtype; param1=value1; param2=value2 ...} where each of the
+ * parameters are optional. Parsing is lenient, malformed parameters are ignored.
+ *
+ * Parameter keys & values are trimmed of whitespace and keys are converted to
+ * lower case.
+ */
+ private static Map<String, String> parseContentTypeParameters(String contentTypeHeader) {
+ Map<String, String> parameters = Collections.EMPTY_MAP;
+
+ String[] fields = contentTypeHeader.split(";");
+ if (fields.length > 1) {
+ parameters = new HashMap<>();
+ // Ignore the first element in the array (the type/subtype).
+ for (int i = 1; i < fields.length; ++i) {
+ final String parameter = fields[i];
+ if (!parameter.isEmpty()) {
+ final String[] components = parameter.split("=");
+ if (components.length != 2) {
+ continue;
+ }
+
+ final String key = components[0].trim().toLowerCase();
+ final String value = components[1].trim();
+ if (key.isEmpty() || value.isEmpty()) {
+ continue;
+ }
+
+ parameters.put(key, value);
+ }
+ }
+ }
+
+ return parameters;
+ }
+}
diff --git a/luni/src/main/java/libcore/net/url/FtpURLConnection.java b/luni/src/main/java/libcore/net/url/FtpURLConnection.java
index 7594c3a..021bfa2 100644
--- a/luni/src/main/java/libcore/net/url/FtpURLConnection.java
+++ b/luni/src/main/java/libcore/net/url/FtpURLConnection.java
@@ -17,6 +17,7 @@
package libcore.net.url;
+import libcore.net.NetworkSecurityPolicy;
import java.io.BufferedInputStream;
import java.io.EOFException;
import java.io.FileNotFoundException;
@@ -103,9 +104,15 @@ public class FtpURLConnection extends URLConnection {
*
* @param url
*/
- protected FtpURLConnection(URL url) {
+ protected FtpURLConnection(URL url) throws IOException {
super(url);
hostName = url.getHost();
+ if (!NetworkSecurityPolicy.isCleartextTrafficPermitted()) {
+ // Cleartext network traffic is not permitted -- refuse this connection.
+ throw new IOException("Cleartext traffic not permitted: "
+ + url.getProtocol() + "://" + hostName
+ + ((url.getPort() >= 0) ? (":" + url.getPort()) : ""));
+ }
String parse = url.getUserInfo();
if (parse != null) {
int split = parse.indexOf(':');
@@ -118,7 +125,7 @@ public class FtpURLConnection extends URLConnection {
}
uri = null;
try {
- uri = url.toURI();
+ uri = url.toURILenient();
} catch (URISyntaxException e) {
// do nothing.
}
@@ -130,7 +137,7 @@ public class FtpURLConnection extends URLConnection {
* @param url
* @param proxy
*/
- protected FtpURLConnection(URL url, Proxy proxy) {
+ protected FtpURLConnection(URL url, Proxy proxy) throws IOException {
this(url);
this.proxy = proxy;
}
diff --git a/luni/src/main/java/java/nio/charset/Charsets.java b/luni/src/main/java/libcore/util/CharsetUtils.java
index 3dede7a..5163dba 100644
--- a/luni/src/main/java/java/nio/charset/Charsets.java
+++ b/luni/src/main/java/libcore/util/CharsetUtils.java
@@ -14,42 +14,42 @@
* limitations under the License.
*/
-package java.nio.charset;
+package libcore.util;
/**
* Various special-case charset conversions (for performance).
*
* @hide internal use only
*/
-public final class Charsets {
+public final class CharsetUtils {
/**
- * Returns a new byte array containing the bytes corresponding to the given characters,
- * encoded in US-ASCII. Unrepresentable characters are replaced by (byte) '?'.
+ * Returns a new byte array containing the bytes corresponding to the characters in the given
+ * string, encoded in US-ASCII. Unrepresentable characters are replaced by (byte) '?'.
*/
- public static native byte[] toAsciiBytes(char[] chars, int offset, int length);
+ public static native byte[] toAsciiBytes(String s, int offset, int length);
/**
- * Returns a new byte array containing the bytes corresponding to the given characters,
- * encoded in ISO-8859-1. Unrepresentable characters are replaced by (byte) '?'.
+ * Returns a new byte array containing the bytes corresponding to the characters in the given
+ * string, encoded in ISO-8859-1. Unrepresentable characters are replaced by (byte) '?'.
*/
- public static native byte[] toIsoLatin1Bytes(char[] chars, int offset, int length);
+ public static native byte[] toIsoLatin1Bytes(String s, int offset, int length);
/**
- * Returns a new byte array containing the bytes corresponding to the given characters,
- * encoded in UTF-8. All characters are representable in UTF-8.
+ * Returns a new byte array containing the bytes corresponding to the characters in the given
+ * string, encoded in UTF-8. All characters are representable in UTF-8.
*/
- public static native byte[] toUtf8Bytes(char[] chars, int offset, int length);
+ public static native byte[] toUtf8Bytes(String s, int offset, int length);
/**
- * Returns a new byte array containing the bytes corresponding to the given characters,
- * encoded in UTF-16BE. All characters are representable in UTF-16BE.
+ * Returns a new byte array containing the bytes corresponding to the characters in the given
+ * string, encoded in UTF-16BE. All characters are representable in UTF-16BE.
*/
- public static byte[] toBigEndianUtf16Bytes(char[] chars, int offset, int length) {
+ public static byte[] toBigEndianUtf16Bytes(String s, int offset, int length) {
byte[] result = new byte[length * 2];
int end = offset + length;
int resultIndex = 0;
for (int i = offset; i < end; ++i) {
- char ch = chars[i];
+ char ch = s.charAt(i);
result[resultIndex++] = (byte) (ch >> 8);
result[resultIndex++] = (byte) ch;
}
@@ -75,6 +75,6 @@ public final class Charsets {
*/
public static native void isoLatin1BytesToChars(byte[] bytes, int offset, int length, char[] chars);
- private Charsets() {
+ private CharsetUtils() {
}
}
diff --git a/luni/src/main/java/libcore/util/CountingOutputStream.java b/luni/src/main/java/libcore/util/CountingOutputStream.java
new file mode 100644
index 0000000..cc0e1f2
--- /dev/null
+++ b/luni/src/main/java/libcore/util/CountingOutputStream.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package libcore.util;
+
+import java.io.FilterOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+
+/**
+ * An output stream that keeps count of the number of bytes written to it.
+ *
+ * Useful when we need to make decisions based on the size of the output, such
+ * as deciding what sort of metadata to writes to zip files.
+ */
+public class CountingOutputStream extends FilterOutputStream {
+
+ private long count;
+
+ /**
+ * Constructs a new {@code FilterOutputStream} with {@code out} as its
+ * target stream.
+ *
+ * @param out the target stream that this stream writes to.
+ */
+ public CountingOutputStream(OutputStream out) {
+ super(out);
+ count = 0;
+ }
+
+ @Override
+ public void write(byte[] buffer, int offset, int length) throws IOException {
+ out.write(buffer, offset, length);
+ count += length;
+ }
+
+ @Override
+ public void write(int oneByte) throws IOException {
+ out.write(oneByte);
+ count++;
+ }
+
+ public long getCount() {
+ return count;
+ }
+}
diff --git a/luni/src/main/java/libcore/util/HexEncoding.java b/luni/src/main/java/libcore/util/HexEncoding.java
new file mode 100644
index 0000000..4c7e7a2
--- /dev/null
+++ b/luni/src/main/java/libcore/util/HexEncoding.java
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package libcore.util;
+
+/**
+ * Hexadecimal encoding where each byte is represented by two hexadecimal digits.
+ */
+public class HexEncoding {
+
+ /** Hidden constructor to prevent instantiation. */
+ private HexEncoding() {}
+
+ private static final char[] HEX_DIGITS = "0123456789ABCDEF".toCharArray();
+
+ /**
+ * Encodes the provided data as a sequence of hexadecimal characters.
+ */
+ public static char[] encode(byte[] data) {
+ return encode(data, 0, data.length);
+ }
+
+ /**
+ * Encodes the provided data as a sequence of hexadecimal characters.
+ */
+ public static char[] encode(byte[] data, int offset, int len) {
+ char[] result = new char[len * 2];
+ for (int i = 0; i < len; i++) {
+ byte b = data[offset + i];
+ int resultIndex = 2 * i;
+ result[resultIndex] = (HEX_DIGITS[(b >>> 4) & 0x0f]);
+ result[resultIndex + 1] = (HEX_DIGITS[b & 0x0f]);
+ }
+
+ return result;
+ }
+
+ /**
+ * Decodes the provided hexadecimal string into a byte array. If {@code allowSingleChar}
+ * is {@code true} odd-length inputs are allowed and the first character is interpreted
+ * as the lower bits of the first result byte.
+ *
+ * Throws an {@code IllegalArgumentException} if the input is malformed.
+ */
+ public static byte[] decode(char[] encoded, boolean allowSingleChar) throws IllegalArgumentException {
+ int resultLengthBytes = (encoded.length + 1) / 2;
+ byte[] result = new byte[resultLengthBytes];
+
+ int resultOffset = 0;
+ int i = 0;
+ if (allowSingleChar) {
+ if ((encoded.length % 2) != 0) {
+ // Odd number of digits -- the first digit is the lower 4 bits of the first result byte.
+ result[resultOffset++] = (byte) toDigit(encoded, i);
+ i++;
+ }
+ } else {
+ if ((encoded.length % 2) != 0) {
+ throw new IllegalArgumentException("Invalid input length: " + encoded.length);
+ }
+ }
+
+ for (int len = encoded.length; i < len; i += 2) {
+ result[resultOffset++] = (byte) ((toDigit(encoded, i) << 4) | toDigit(encoded, i + 1));
+ }
+
+ return result;
+ }
+
+ private static int toDigit(char[] str, int offset) throws IllegalArgumentException {
+ // NOTE: that this isn't really a code point in the traditional sense, since we're
+ // just rejecting surrogate pairs outright.
+ int pseudoCodePoint = str[offset];
+
+ if ('0' <= pseudoCodePoint && pseudoCodePoint <= '9') {
+ return pseudoCodePoint - '0';
+ } else if ('a' <= pseudoCodePoint && pseudoCodePoint <= 'f') {
+ return 10 + (pseudoCodePoint - 'a');
+ } else if ('A' <= pseudoCodePoint && pseudoCodePoint <= 'F') {
+ return 10 + (pseudoCodePoint - 'A');
+ }
+
+ throw new IllegalArgumentException("Illegal char: " + str[offset] +
+ " at offset " + offset);
+ }
+}
diff --git a/luni/src/main/java/libcore/util/ZoneInfo.java b/luni/src/main/java/libcore/util/ZoneInfo.java
index 4d58d93..329320d 100644
--- a/luni/src/main/java/libcore/util/ZoneInfo.java
+++ b/luni/src/main/java/libcore/util/ZoneInfo.java
@@ -54,7 +54,7 @@ public final class ZoneInfo extends TimeZone {
private final boolean mUseDst;
private final int mDstSavings; // Implements TimeZone.getDSTSavings.
- private final int[] mTransitions;
+ private final long[] mTransitions;
private final int[] mOffsets;
private final byte[] mTypes;
private final byte[] mIsDsts;
@@ -76,8 +76,19 @@ public final class ZoneInfo extends TimeZone {
it.skip(4); // Skip tzh_charcnt.
- int[] transitions = new int[tzh_timecnt];
- it.readIntArray(transitions, 0, transitions.length);
+ // Transitions are signed 32 bit integers, but we store them as signed 64 bit
+ // integers since it's easier to compare them against 64 bit inputs (see getOffset
+ // and isDaylightTime) with much less risk of an overflow in our calculations.
+ //
+ // The alternative of checking the input against the first and last transition in
+ // the array is far more awkward and error prone.
+ int[] transitions32 = new int[tzh_timecnt];
+ it.readIntArray(transitions32, 0, transitions32.length);
+
+ long[] transitions64 = new long[tzh_timecnt];
+ for (int i = 0; i < tzh_timecnt; ++i) {
+ transitions64[i] = transitions32[i];
+ }
byte[] type = new byte[tzh_timecnt];
it.readByteArray(type, 0, type.length);
@@ -97,10 +108,10 @@ public final class ZoneInfo extends TimeZone {
it.skip(1);
}
- return new ZoneInfo(id, transitions, type, gmtOffsets, isDsts);
+ return new ZoneInfo(id, transitions64, type, gmtOffsets, isDsts);
}
- private ZoneInfo(String name, int[] transitions, byte[] types, int[] gmtOffsets, byte[] isDsts) {
+ private ZoneInfo(String name, long[] transitions, byte[] types, int[] gmtOffsets, byte[] isDsts) {
mTransitions = transitions;
mTypes = types;
mIsDsts = isDsts;
@@ -163,7 +174,7 @@ public final class ZoneInfo extends TimeZone {
// no future plans (and thus no future schedule info) will report "true" from
// useDaylightTime at the start of 2009 but "false" at the end. This seems appropriate.
boolean usesDst = false;
- int currentUnixTimeSeconds = (int) (System.currentTimeMillis() / 1000);
+ long currentUnixTimeSeconds = System.currentTimeMillis() / 1000;
int i = mTransitions.length - 1;
while (i >= 0 && mTransitions[i] >= currentUnixTimeSeconds) {
if (mIsDsts[mTypes[i]] > 0) {
@@ -210,7 +221,7 @@ public final class ZoneInfo extends TimeZone {
@Override
public int getOffset(long when) {
- int unix = (int) (when / 1000);
+ long unix = when / 1000;
int transition = Arrays.binarySearch(mTransitions, unix);
if (transition < 0) {
transition = ~transition - 1;
@@ -226,7 +237,7 @@ public final class ZoneInfo extends TimeZone {
@Override public boolean inDaylightTime(Date time) {
long when = time.getTime();
- int unix = (int) (when / 1000);
+ long unix = when / 1000;
int transition = Arrays.binarySearch(mTransitions, unix);
if (transition < 0) {
transition = ~transition - 1;
@@ -952,9 +963,9 @@ public final class ZoneInfo extends TimeZone {
*
* @throws CheckedArithmeticException if overflow or underflow occurs
*/
- private static int checkedAdd(int a, int b) throws CheckedArithmeticException {
+ private static int checkedAdd(long a, int b) throws CheckedArithmeticException {
// Adapted from Guava IntMath.checkedAdd();
- long result = (long) a + b;
+ long result = a + b;
if (result != (int) result) {
throw new CheckedArithmeticException();
}
diff --git a/luni/src/main/java/libcore/util/ZoneInfoDB.java b/luni/src/main/java/libcore/util/ZoneInfoDB.java
index 906ec14..fd8570c 100644
--- a/luni/src/main/java/libcore/util/ZoneInfoDB.java
+++ b/luni/src/main/java/libcore/util/ZoneInfoDB.java
@@ -41,7 +41,8 @@ import libcore.io.MemoryMappedFile;
*/
public final class ZoneInfoDB {
private static final TzData DATA =
- new TzData(System.getenv("ANDROID_ROOT") + "/usr/share/zoneinfo/tzdata");
+ new TzData(System.getenv("ANDROID_DATA") + "/misc/zoneinfo/current/tzdata",
+ System.getenv("ANDROID_ROOT") + "/usr/share/zoneinfo/tzdata");
public static class TzData {
/**
@@ -248,6 +249,10 @@ public final class ZoneInfoDB {
// The object from the cache is cloned because TimeZone / ZoneInfo are mutable.
return zoneInfo == null ? null : (ZoneInfo) zoneInfo.clone();
}
+
+ public boolean hasTimeZone(String id) throws IOException {
+ return cache.get(id) != null;
+ }
}
private ZoneInfoDB() {
diff --git a/luni/src/main/java/org/apache/harmony/security/fortress/Engine.java b/luni/src/main/java/org/apache/harmony/security/fortress/Engine.java
index 855a8c7..1c794e5 100644
--- a/luni/src/main/java/org/apache/harmony/security/fortress/Engine.java
+++ b/luni/src/main/java/org/apache/harmony/security/fortress/Engine.java
@@ -152,7 +152,8 @@ public final class Engine {
}
/**
- * Returns a list of all possible matches for a given algorithm.
+ * Returns a list of all possible matches for a given algorithm. Returns
+ * {@code null} if no matches were found.
*/
public ArrayList<Provider.Service> getServices(String algorithm) {
int newCacheVersion = Services.getCacheVersion();
@@ -163,8 +164,7 @@ public final class Engine {
&& newCacheVersion == cacheEntry.cacheVersion) {
return cacheEntry.services;
}
- String name = this.serviceName + "." + algoUC;
- ArrayList<Provider.Service> services = Services.getServices(name);
+ ArrayList<Provider.Service> services = Services.getServices(serviceName, algoUC);
this.serviceCache = new ServiceCacheEntry(algoUC, newCacheVersion, services);
return services;
}
diff --git a/luni/src/main/java/org/apache/harmony/security/fortress/Services.java b/luni/src/main/java/org/apache/harmony/security/fortress/Services.java
index 30f4839..234f4a2 100644
--- a/luni/src/main/java/org/apache/harmony/security/fortress/Services.java
+++ b/luni/src/main/java/org/apache/harmony/security/fortress/Services.java
@@ -29,16 +29,6 @@ import java.util.Locale;
* implementations for all "serviceName.algName".
*/
public class Services {
-
- /**
- * The HashMap that contains information about preferred implementations for
- * all serviceName.algName in the registered providers.
- * Set the initial size to 600 so we don't grow to 1024 by default because
- * initialization adds a few entries more than the growth threshold.
- */
- private static final HashMap<String, ArrayList<Provider.Service>> services
- = new HashMap<String, ArrayList<Provider.Service>>(600);
-
/**
* Save default SecureRandom service as well.
* Avoids similar provider/services iteration in SecureRandom constructor.
@@ -63,6 +53,23 @@ public class Services {
private static final ArrayList<Provider> providers = new ArrayList<Provider>(20);
/**
+ * Try to load and register a provider by name from the given class-loader.
+ */
+ private static boolean initProvider(String providerClassName, ClassLoader classLoader) {
+ try {
+ Class<?> providerClass = Class.forName(providerClassName.trim(), true, classLoader);
+ Provider p = (Provider) providerClass.newInstance();
+ providers.add(p);
+ providersNames.put(p.getName(), p);
+ return true;
+ } catch (ClassNotFoundException ignored) {
+ } catch (IllegalAccessException ignored) {
+ } catch (InstantiationException ignored) {
+ }
+ return false;
+ }
+
+ /**
* Hash for quick provider access by name.
*/
private static final HashMap<String, Provider> providersNames
@@ -70,25 +77,24 @@ public class Services {
static {
String providerClassName = null;
int i = 1;
- ClassLoader cl = ClassLoader.getSystemClassLoader();
+ ClassLoader cl = Services.class.getClassLoader();
while ((providerClassName = Security.getProperty("security.provider." + i++)) != null) {
- try {
- Class<?> providerClass = Class.forName(providerClassName.trim(), true, cl);
- Provider p = (Provider) providerClass.newInstance();
- providers.add(p);
- providersNames.put(p.getName(), p);
- initServiceInfo(p);
- } catch (ClassNotFoundException ignored) {
- } catch (IllegalAccessException ignored) {
- } catch (InstantiationException ignored) {
+ if (!initProvider(providerClassName, cl)) {
+ // Not on the boot classpath. Try the system class-loader.
+ // Note: DO NOT USE A LOCAL FOR GETSYSTEMCLASSLOADER! This will break compile-time
+ // initialization.
+ if (!initProvider(providerClassName, ClassLoader.getSystemClassLoader())) {
+ // TODO: Logging?
+ }
}
}
Engine.door.renumProviders();
+ setNeedRefresh();
}
/**
- * Returns a copy of the registered providers as an array.
+ * Returns the actual registered providers.
*/
public static synchronized ArrayList<Provider> getProviders() {
return providers;
@@ -128,54 +134,39 @@ public class Services {
}
/**
- * Adds information about provider services into HashMap.
- */
- public static synchronized void initServiceInfo(Provider p) {
- for (Provider.Service service : p.getServices()) {
- String type = service.getType();
- if (cachedSecureRandomService == null && type.equals("SecureRandom")) {
- cachedSecureRandomService = service;
- }
- String key = type + "." + service.getAlgorithm().toUpperCase(Locale.US);
- appendServiceLocked(key, service);
- for (String alias : Engine.door.getAliases(service)) {
- key = type + "." + alias.toUpperCase(Locale.US);
- appendServiceLocked(key, service);
+ * Looks up the requested service by type and algorithm. The service
+ * {@code type} and should be provided in the same format used when
+ * registering a service with a provider, for example, "KeyFactory.RSA".
+ * Callers can cache the returned service information but such caches should
+ * be validated against the result of Service.getCacheVersion() before use.
+ * Returns {@code null} if there are no services found.
+ */
+ public static synchronized ArrayList<Provider.Service> getServices(String type,
+ String algorithm) {
+ ArrayList<Provider.Service> services = null;
+ for (Provider p : providers) {
+ Provider.Service s = p.getService(type, algorithm);
+ if (s != null) {
+ if (services == null) {
+ services = new ArrayList<>(providers.size());
+ }
+ services.add(s);
}
}
+ return services;
}
/**
- * Add or append the service to the key.
+ * Finds the first service offered of {@code type} and returns it.
*/
- private static void appendServiceLocked(String key, Provider.Service service) {
- ArrayList<Provider.Service> serviceList = services.get(key);
- if (serviceList == null) {
- serviceList = new ArrayList<Provider.Service>(1);
- services.put(key, serviceList);
+ private static synchronized Provider.Service getFirstServiceOfType(String type) {
+ for (Provider p : providers) {
+ Provider.Service s = Engine.door.getService(p, type);
+ if (s != null) {
+ return s;
+ }
}
- serviceList.add(service);
- }
-
- /**
- * Returns true if services does not contain any provider information.
- */
- public static synchronized boolean isEmpty() {
- return services.isEmpty();
- }
-
- /**
- * Looks up the requested service by type and algorithm. The
- * service key should be provided in the same format used when
- * registering a service with a provider, for example,
- * "KeyFactory.RSA".
- *
- * Callers can cache the returned service information but such
- * caches should be validated against the result of
- * Service.getCacheVersion() before use.
- */
- public static synchronized ArrayList<Provider.Service> getServices(String key) {
- return services.get(key);
+ return null;
}
/**
@@ -203,13 +194,7 @@ public class Services {
public static synchronized int getCacheVersion() {
if (needRefresh) {
cacheVersion++;
- synchronized (services) {
- services.clear();
- }
- cachedSecureRandomService = null;
- for (Provider p : providers) {
- initServiceInfo(p);
- }
+ cachedSecureRandomService = getFirstServiceOfType("SecureRandom");
needRefresh = false;
}
return cacheVersion;
diff --git a/luni/src/main/java/org/apache/harmony/security/utils/JarUtils.java b/luni/src/main/java/org/apache/harmony/security/utils/JarUtils.java
index 917a3a8..020663e 100644
--- a/luni/src/main/java/org/apache/harmony/security/utils/JarUtils.java
+++ b/luni/src/main/java/org/apache/harmony/security/utils/JarUtils.java
@@ -198,8 +198,8 @@ public class JarUtils {
}
}
- // RFC 3852 section 9.2: it authAttrs is present, it must have a
- // message digest entry.
+ // RFC 2315 section 9.1: if authenticatedAttributes is present, it
+ // must have a message-digest attribute.
if (existingDigest == null) {
throw new SecurityException("Missing MessageDigest in Authenticated Attributes");
}
diff --git a/luni/src/main/java/org/apache/harmony/security/utils/WrappedX509Certificate.java b/luni/src/main/java/org/apache/harmony/security/utils/WrappedX509Certificate.java
index 2b09309..1c07915 100644
--- a/luni/src/main/java/org/apache/harmony/security/utils/WrappedX509Certificate.java
+++ b/luni/src/main/java/org/apache/harmony/security/utils/WrappedX509Certificate.java
@@ -160,7 +160,7 @@ public class WrappedX509Certificate extends X509Certificate {
public void verify(PublicKey key, String sigProvider) throws CertificateException,
NoSuchAlgorithmException, InvalidKeyException, NoSuchProviderException,
SignatureException {
- verify(key, sigProvider);
+ wrapped.verify(key, sigProvider);
}
@Override
diff --git a/luni/src/main/native/IcuUtilities.cpp b/luni/src/main/native/IcuUtilities.cpp
index 7ce2168..98648a5 100644
--- a/luni/src/main/native/IcuUtilities.cpp
+++ b/luni/src/main/native/IcuUtilities.cpp
@@ -22,13 +22,12 @@
#include "JniException.h"
#include "ScopedLocalRef.h"
#include "ScopedUtfChars.h"
-#include "UniquePtr.h"
#include "cutils/log.h"
#include "unicode/strenum.h"
#include "unicode/uloc.h"
#include "unicode/ustring.h"
-jobjectArray fromStringEnumeration(JNIEnv* env, UErrorCode& status, const char* provider, StringEnumeration* se) {
+jobjectArray fromStringEnumeration(JNIEnv* env, UErrorCode& status, const char* provider, icu::StringEnumeration* se) {
if (maybeThrowIcuException(env, provider, status)) {
return NULL;
}
@@ -40,7 +39,7 @@ jobjectArray fromStringEnumeration(JNIEnv* env, UErrorCode& status, const char*
jobjectArray result = env->NewObjectArray(count, JniConstants::stringClass, NULL);
for (int32_t i = 0; i < count; ++i) {
- const UnicodeString* string = se->snext(status);
+ const icu::UnicodeString* string = se->snext(status);
if (maybeThrowIcuException(env, "StringEnumeration::snext", status)) {
return NULL;
}
diff --git a/luni/src/main/native/IcuUtilities.h b/luni/src/main/native/IcuUtilities.h
index 737379e..c64de30 100644
--- a/luni/src/main/native/IcuUtilities.h
+++ b/luni/src/main/native/IcuUtilities.h
@@ -17,14 +17,11 @@
#ifndef ICU_UTILITIES_H_included
#define ICU_UTILITIES_H_included
-#undef U_HAVE_STD_STRING
-#define U_HAVE_STD_STRING 1 // For UnicodeString::toUTF8String(std::string&).
-
#include "jni.h"
#include "ustrenum.h" // For UStringEnumeration.
#include "unicode/utypes.h" // For UErrorCode.
-extern jobjectArray fromStringEnumeration(JNIEnv* env, UErrorCode& status, const char* provider, StringEnumeration*);
+extern jobjectArray fromStringEnumeration(JNIEnv* env, UErrorCode& status, const char* provider, icu::StringEnumeration*);
bool maybeThrowIcuException(JNIEnv* env, const char* function, UErrorCode error);
#endif // ICU_UTILITIES_H_included
diff --git a/luni/src/main/native/Portability.h b/luni/src/main/native/Portability.h
index 1520311..5900cb0 100644
--- a/luni/src/main/native/Portability.h
+++ b/luni/src/main/native/Portability.h
@@ -65,7 +65,7 @@ static inline int mincore(void* addr, size_t length, unsigned char* vec) {
#include <sys/param.h>
#include <sys/mount.h>
-#else // defined(__APPLE__)
+#else
// Bionic or glibc.
@@ -73,15 +73,33 @@ static inline int mincore(void* addr, size_t length, unsigned char* vec) {
#include <sys/sendfile.h>
#include <sys/statvfs.h>
-#endif // defined(__APPLE__)
+#endif
-#if !defined(__BIONIC__)
#include <netdb.h>
-#include "../../bionic/libc/dns/include/resolv_netid.h"
-inline int android_getaddrinfofornet(const char *hostname, const char *servname,
- const struct addrinfo *hints, unsigned /*netid*/, unsigned /*mark*/, struct addrinfo **res) {
+#if defined(__BIONIC__)
+extern "C" int android_getaddrinfofornet(const char*, const char*, const struct addrinfo*, unsigned, unsigned, struct addrinfo**);
+#else
+static inline int android_getaddrinfofornet(const char* hostname, const char* servname,
+ const struct addrinfo* hints, unsigned /*netid*/, unsigned /*mark*/, struct addrinfo** res) {
return getaddrinfo(hostname, servname, hints, res);
}
-#endif // !defined(__BIONIC__)
+#endif
+
+#if defined(__GLIBC__) && !defined(__LP64__)
+
+#include <unistd.h>
+
+// 32 bit GLIBC hardcodes a "long int" as the return type for
+// TEMP_FAILURE_RETRY so the return value here gets truncated for
+// functions that return 64 bit types.
+#undef TEMP_FAILURE_RETRY
+#define TEMP_FAILURE_RETRY(exp) ({ \
+ __typeof__(exp) _rc; \
+ do { \
+ _rc = (exp); \
+ } while (_rc == -1 && errno == EINTR); \
+ _rc; })
+
+#endif // __GLIBC__ && !__LP64__
#endif // PORTABILITY_H_included
diff --git a/luni/src/main/native/Register.cpp b/luni/src/main/native/Register.cpp
index 6a2c939..acc1e4f 100644
--- a/luni/src/main/native/Register.cpp
+++ b/luni/src/main/native/Register.cpp
@@ -48,7 +48,6 @@ jint JNI_OnLoad(JavaVM* vm, void*) {
REGISTER(register_java_lang_System);
REGISTER(register_java_math_NativeBN);
REGISTER(register_java_nio_ByteOrder);
- REGISTER(register_java_nio_charset_Charsets);
REGISTER(register_java_text_Bidi);
REGISTER(register_java_util_jar_StrictJarFile);
REGISTER(register_java_util_regex_Matcher);
@@ -58,9 +57,7 @@ jint JNI_OnLoad(JavaVM* vm, void*) {
REGISTER(register_java_util_zip_Deflater);
REGISTER(register_java_util_zip_Inflater);
REGISTER(register_libcore_icu_AlphabeticIndex);
- REGISTER(register_libcore_icu_DateIntervalFormat);
REGISTER(register_libcore_icu_ICU);
- REGISTER(register_libcore_icu_NativeBreakIterator);
REGISTER(register_libcore_icu_NativeCollation);
REGISTER(register_libcore_icu_NativeConverter);
REGISTER(register_libcore_icu_NativeDecimalFormat);
diff --git a/luni/src/main/native/ZipUtilities.cpp b/luni/src/main/native/ZipUtilities.cpp
index 745b3b1..b7d2209 100644
--- a/luni/src/main/native/ZipUtilities.cpp
+++ b/luni/src/main/native/ZipUtilities.cpp
@@ -15,9 +15,10 @@
* limitations under the License.
*/
+#include <memory>
+
#include "JniConstants.h"
#include "JniException.h"
-#include "UniquePtr.h"
#include "ZipUtilities.h"
void throwExceptionForZlibError(JNIEnv* env, const char* exceptionClassName, int error,
@@ -31,7 +32,7 @@ void throwExceptionForZlibError(JNIEnv* env, const char* exceptionClassName, int
}
}
-NativeZipStream::NativeZipStream() : input(NULL), inCap(0), mDict(NULL) {
+NativeZipStream::NativeZipStream() : inCap(0), totalIn(0), totalOut(0) {
// Let zlib use its default allocator.
stream.opaque = Z_NULL;
stream.zalloc = Z_NULL;
@@ -43,7 +44,7 @@ NativeZipStream::~NativeZipStream() {
void NativeZipStream::setDictionary(JNIEnv* env, jbyteArray javaDictionary, int off, int len,
bool inflate) {
- UniquePtr<jbyte[]> dictionaryBytes(new jbyte[len]);
+ std::unique_ptr<jbyte[]> dictionaryBytes(new jbyte[len]);
if (dictionaryBytes.get() == NULL) {
jniThrowOutOfMemoryError(env, NULL);
return;
diff --git a/luni/src/main/native/ZipUtilities.h b/luni/src/main/native/ZipUtilities.h
index fe0f977..50111a5 100644
--- a/luni/src/main/native/ZipUtilities.h
+++ b/luni/src/main/native/ZipUtilities.h
@@ -18,15 +18,18 @@
#ifndef ZIP_UTILITIES_H_included
#define ZIP_UTILITIES_H_included
-#include "UniquePtr.h"
+#include <cstdint>
+#include <memory>
#include "jni.h"
#include "zlib.h"
class NativeZipStream {
public:
- UniquePtr<jbyte[]> input;
+ std::unique_ptr<jbyte[]> input;
int inCap;
z_stream stream;
+ uint64_t totalIn;
+ uint64_t totalOut;
NativeZipStream();
~NativeZipStream();
@@ -34,7 +37,7 @@ public:
void setInput(JNIEnv* env, jbyteArray buf, jint off, jint len);
private:
- UniquePtr<jbyte[]> mDict;
+ std::unique_ptr<jbyte[]> mDict;
// Disallow copy and assignment.
NativeZipStream(const NativeZipStream&);
diff --git a/luni/src/main/native/android_system_OsConstants.cpp b/luni/src/main/native/android_system_OsConstants.cpp
index 92212b9..a11ea76 100644
--- a/luni/src/main/native/android_system_OsConstants.cpp
+++ b/luni/src/main/native/android_system_OsConstants.cpp
@@ -36,8 +36,12 @@
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/wait.h>
+#include <sys/xattr.h>
#include <unistd.h>
+#include <net/if_arp.h>
+#include <linux/if_ether.h>
+
// After the others because these are not necessarily self-contained in glibc.
#ifndef __APPLE__
#include <linux/if_addr.h>
@@ -58,6 +62,8 @@ static void initConstant(JNIEnv* env, jclass c, const char* fieldName, int value
static void OsConstants_initConstants(JNIEnv* env, jclass c) {
initConstant(env, c, "AF_INET", AF_INET);
initConstant(env, c, "AF_INET6", AF_INET6);
+ initConstant(env, c, "AF_PACKET", AF_PACKET);
+ initConstant(env, c, "AF_NETLINK", AF_NETLINK);
initConstant(env, c, "AF_UNIX", AF_UNIX);
initConstant(env, c, "AF_UNSPEC", AF_UNSPEC);
initConstant(env, c, "AI_ADDRCONFIG", AI_ADDRCONFIG);
@@ -69,6 +75,8 @@ static void OsConstants_initConstants(JNIEnv* env, jclass c) {
#endif
initConstant(env, c, "AI_PASSIVE", AI_PASSIVE);
initConstant(env, c, "AI_V4MAPPED", AI_V4MAPPED);
+ initConstant(env, c, "ARPHRD_ETHER", ARPHRD_ETHER);
+ initConstant(env, c, "ARPHRD_LOOPBACK", ARPHRD_LOOPBACK);
#if defined(CAP_LAST_CAP)
initConstant(env, c, "CAP_AUDIT_CONTROL", CAP_AUDIT_CONTROL);
initConstant(env, c, "CAP_AUDIT_WRITE", CAP_AUDIT_WRITE);
@@ -172,6 +180,7 @@ static void OsConstants_initConstants(JNIEnv* env, jclass c) {
initConstant(env, c, "ENOLINK", ENOLINK);
initConstant(env, c, "ENOMEM", ENOMEM);
initConstant(env, c, "ENOMSG", ENOMSG);
+ initConstant(env, c, "ENONET", ENONET);
initConstant(env, c, "ENOPROTOOPT", ENOPROTOOPT);
initConstant(env, c, "ENOSPC", ENOSPC);
initConstant(env, c, "ENOSR", ENOSR);
@@ -196,6 +205,9 @@ static void OsConstants_initConstants(JNIEnv* env, jclass c) {
initConstant(env, c, "ESPIPE", ESPIPE);
initConstant(env, c, "ESRCH", ESRCH);
initConstant(env, c, "ESTALE", ESTALE);
+ initConstant(env, c, "ETH_P_ARP", ETH_P_ARP);
+ initConstant(env, c, "ETH_P_IP", ETH_P_IP);
+ initConstant(env, c, "ETH_P_IPV6", ETH_P_IPV6);
initConstant(env, c, "ETIME", ETIME);
initConstant(env, c, "ETIMEDOUT", ETIMEDOUT);
initConstant(env, c, "ETXTBSY", ETXTBSY);
@@ -355,6 +367,7 @@ static void OsConstants_initConstants(JNIEnv* env, jclass c) {
initConstant(env, c, "MS_ASYNC", MS_ASYNC);
initConstant(env, c, "MS_INVALIDATE", MS_INVALIDATE);
initConstant(env, c, "MS_SYNC", MS_SYNC);
+ initConstant(env, c, "NETLINK_ROUTE", NETLINK_ROUTE);
initConstant(env, c, "NI_DGRAM", NI_DGRAM);
initConstant(env, c, "NI_NAMEREQD", NI_NAMEREQD);
initConstant(env, c, "NI_NOFQDN", NI_NOFQDN);
@@ -362,6 +375,7 @@ static void OsConstants_initConstants(JNIEnv* env, jclass c) {
initConstant(env, c, "NI_NUMERICSERV", NI_NUMERICSERV);
initConstant(env, c, "O_ACCMODE", O_ACCMODE);
initConstant(env, c, "O_APPEND", O_APPEND);
+ initConstant(env, c, "O_CLOEXEC", O_CLOEXEC);
initConstant(env, c, "O_CREAT", O_CREAT);
initConstant(env, c, "O_EXCL", O_EXCL);
initConstant(env, c, "O_NOCTTY", O_NOCTTY);
@@ -406,6 +420,19 @@ static void OsConstants_initConstants(JNIEnv* env, jclass c) {
initConstant(env, c, "RT_SCOPE_NOWHERE", RT_SCOPE_NOWHERE);
initConstant(env, c, "RT_SCOPE_SITE", RT_SCOPE_SITE);
initConstant(env, c, "RT_SCOPE_UNIVERSE", RT_SCOPE_UNIVERSE);
+ initConstant(env, c, "RTMGRP_IPV4_IFADDR", RTMGRP_IPV4_IFADDR);
+ initConstant(env, c, "RTMGRP_IPV4_MROUTE", RTMGRP_IPV4_MROUTE);
+ initConstant(env, c, "RTMGRP_IPV4_ROUTE", RTMGRP_IPV4_ROUTE);
+ initConstant(env, c, "RTMGRP_IPV4_RULE", RTMGRP_IPV4_RULE);
+ initConstant(env, c, "RTMGRP_IPV6_IFADDR", RTMGRP_IPV6_IFADDR);
+ initConstant(env, c, "RTMGRP_IPV6_IFINFO", RTMGRP_IPV6_IFINFO);
+ initConstant(env, c, "RTMGRP_IPV6_MROUTE", RTMGRP_IPV6_MROUTE);
+ initConstant(env, c, "RTMGRP_IPV6_PREFIX", RTMGRP_IPV6_PREFIX);
+ initConstant(env, c, "RTMGRP_IPV6_ROUTE", RTMGRP_IPV6_ROUTE);
+ initConstant(env, c, "RTMGRP_LINK", RTMGRP_LINK);
+ initConstant(env, c, "RTMGRP_NEIGH", RTMGRP_NEIGH);
+ initConstant(env, c, "RTMGRP_NOTIFY", RTMGRP_NOTIFY);
+ initConstant(env, c, "RTMGRP_TC", RTMGRP_TC);
#endif
initConstant(env, c, "SEEK_CUR", SEEK_CUR);
initConstant(env, c, "SEEK_END", SEEK_END);
@@ -490,6 +517,15 @@ static void OsConstants_initConstants(JNIEnv* env, jclass c) {
initConstant(env, c, "STDERR_FILENO", STDERR_FILENO);
initConstant(env, c, "STDIN_FILENO", STDIN_FILENO);
initConstant(env, c, "STDOUT_FILENO", STDOUT_FILENO);
+ initConstant(env, c, "ST_MANDLOCK", ST_MANDLOCK);
+ initConstant(env, c, "ST_NOATIME", ST_NOATIME);
+ initConstant(env, c, "ST_NODEV", ST_NODEV);
+ initConstant(env, c, "ST_NODIRATIME", ST_NODIRATIME);
+ initConstant(env, c, "ST_NOEXEC", ST_NOEXEC);
+ initConstant(env, c, "ST_NOSUID", ST_NOSUID);
+ initConstant(env, c, "ST_RDONLY", ST_RDONLY);
+ initConstant(env, c, "ST_RELATIME", ST_RELATIME);
+ initConstant(env, c, "ST_SYNCHRONOUS", ST_SYNCHRONOUS);
initConstant(env, c, "S_IFBLK", S_IFBLK);
initConstant(env, c, "S_IFCHR", S_IFCHR);
initConstant(env, c, "S_IFDIR", S_IFDIR);
@@ -521,6 +557,8 @@ static void OsConstants_initConstants(JNIEnv* env, jclass c) {
initConstant(env, c, "WSTOPPED", WSTOPPED);
initConstant(env, c, "WUNTRACED", WUNTRACED);
initConstant(env, c, "W_OK", W_OK);
+ initConstant(env, c, "XATTR_CREATE", XATTR_CREATE);
+ initConstant(env, c, "XATTR_REPLACE", XATTR_REPLACE);
initConstant(env, c, "X_OK", X_OK);
initConstant(env, c, "_SC_2_CHAR_TERM", _SC_2_CHAR_TERM);
initConstant(env, c, "_SC_2_C_BIND", _SC_2_C_BIND);
diff --git a/luni/src/main/native/java_lang_RealToString.cpp b/luni/src/main/native/java_lang_RealToString.cpp
index 7036fe8..9b412b5 100644
--- a/luni/src/main/native/java_lang_RealToString.cpp
+++ b/luni/src/main/native/java_lang_RealToString.cpp
@@ -80,7 +80,7 @@ void RealToString_bigIntDigitGenerator(JNIEnv* env, jobject obj, jlong f, jint e
*R = f;
*mplus = *mminus = 1;
simpleShiftLeftHighPrecision (mminus, RM_SIZE, e);
- if (f != (2 << (p - 1)))
+ if (f != (INT64_C(1) << p))
{
simpleShiftLeftHighPrecision (R, RM_SIZE, e + 1);
*S = 2;
@@ -103,7 +103,7 @@ void RealToString_bigIntDigitGenerator(JNIEnv* env, jobject obj, jlong f, jint e
}
else
{
- if (isDenormalized || (f != (2 << (p - 1))))
+ if (isDenormalized || (f != (INT64_C(1) << p)))
{
*R = f << 1;
*S = 1;
diff --git a/luni/src/main/native/java_lang_StrictMath.cpp b/luni/src/main/native/java_lang_StrictMath.cpp
index cfe375e..e8c6dfb 100644
--- a/luni/src/main/native/java_lang_StrictMath.cpp
+++ b/luni/src/main/native/java_lang_StrictMath.cpp
@@ -34,26 +34,6 @@ static jdouble StrictMath_tan(JNIEnv*, jclass, jdouble a) {
return ieee_tan(a);
}
-static jdouble StrictMath_asin(JNIEnv*, jclass, jdouble a) {
- return ieee_asin(a);
-}
-
-static jdouble StrictMath_acos(JNIEnv*, jclass, jdouble a) {
- return ieee_acos(a);
-}
-
-static jdouble StrictMath_atan(JNIEnv*, jclass, jdouble a) {
- return ieee_atan(a);
-}
-
-static jdouble StrictMath_exp(JNIEnv*, jclass, jdouble a) {
- return ieee_exp(a);
-}
-
-static jdouble StrictMath_log(JNIEnv*, jclass, jdouble a) {
- return ieee_log(a);
-}
-
static jdouble StrictMath_sqrt(JNIEnv*, jclass, jdouble a) {
return ieee_sqrt(a);
}
@@ -74,75 +54,30 @@ static jdouble StrictMath_rint(JNIEnv*, jclass, jdouble a) {
return ieee_rint(a);
}
-static jdouble StrictMath_atan2(JNIEnv*, jclass, jdouble a, jdouble b) {
- return ieee_atan2(a, b);
-}
-
static jdouble StrictMath_pow(JNIEnv*, jclass, jdouble a, jdouble b) {
return ieee_pow(a,b);
}
-static jdouble StrictMath_sinh(JNIEnv*, jclass, jdouble a) {
- return ieee_sinh(a);
-}
-
-static jdouble StrictMath_tanh(JNIEnv*, jclass, jdouble a) {
- return ieee_tanh(a);
-}
-
-static jdouble StrictMath_cosh(JNIEnv*, jclass, jdouble a) {
- return ieee_cosh(a);
-}
-
-static jdouble StrictMath_log10(JNIEnv*, jclass, jdouble a) {
- return ieee_log10(a);
-}
-
-static jdouble StrictMath_cbrt(JNIEnv*, jclass, jdouble a) {
- return ieee_cbrt(a);
-}
-
-static jdouble StrictMath_expm1(JNIEnv*, jclass, jdouble a) {
- return ieee_expm1(a);
-}
-
static jdouble StrictMath_hypot(JNIEnv*, jclass, jdouble a, jdouble b) {
return ieee_hypot(a, b);
}
-static jdouble StrictMath_log1p(JNIEnv*, jclass, jdouble a) {
- return ieee_log1p(a);
-}
-
static jdouble StrictMath_nextafter(JNIEnv*, jclass, jdouble a, jdouble b) {
return ieee_nextafter(a, b);
}
static JNINativeMethod gMethods[] = {
NATIVE_METHOD(StrictMath, IEEEremainder, "!(DD)D"),
- NATIVE_METHOD(StrictMath, acos, "!(D)D"),
- NATIVE_METHOD(StrictMath, asin, "!(D)D"),
- NATIVE_METHOD(StrictMath, atan, "!(D)D"),
- NATIVE_METHOD(StrictMath, atan2, "!(DD)D"),
- NATIVE_METHOD(StrictMath, cbrt, "!(D)D"),
NATIVE_METHOD(StrictMath, ceil, "!(D)D"),
NATIVE_METHOD(StrictMath, cos, "!(D)D"),
- NATIVE_METHOD(StrictMath, cosh, "!(D)D"),
- NATIVE_METHOD(StrictMath, exp, "!(D)D"),
- NATIVE_METHOD(StrictMath, expm1, "!(D)D"),
NATIVE_METHOD(StrictMath, floor, "!(D)D"),
NATIVE_METHOD(StrictMath, hypot, "!(DD)D"),
- NATIVE_METHOD(StrictMath, log, "!(D)D"),
- NATIVE_METHOD(StrictMath, log10, "!(D)D"),
- NATIVE_METHOD(StrictMath, log1p, "!(D)D"),
NATIVE_METHOD(StrictMath, nextafter, "!(DD)D"),
NATIVE_METHOD(StrictMath, pow, "!(DD)D"),
NATIVE_METHOD(StrictMath, rint, "!(D)D"),
NATIVE_METHOD(StrictMath, sin, "!(D)D"),
- NATIVE_METHOD(StrictMath, sinh, "!(D)D"),
NATIVE_METHOD(StrictMath, sqrt, "!(D)D"),
NATIVE_METHOD(StrictMath, tan, "!(D)D"),
- NATIVE_METHOD(StrictMath, tanh, "!(D)D"),
};
void register_java_lang_StrictMath(JNIEnv* env) {
jniRegisterNativeMethods(env, "java/lang/StrictMath", gMethods, NELEM(gMethods));
diff --git a/luni/src/main/native/java_lang_StringToReal.cpp b/luni/src/main/native/java_lang_StringToReal.cpp
index 108f939..d1902af 100644
--- a/luni/src/main/native/java_lang_StringToReal.cpp
+++ b/luni/src/main/native/java_lang_StringToReal.cpp
@@ -25,9 +25,6 @@
#include "cbigint.h"
/* ************************* Defines ************************* */
-#if defined(__linux__) || defined(__APPLE__)
-#define USE_LL
-#endif
#define LOW_I32_FROM_VAR(u64) LOW_I32_FROM_LONG64(u64)
#define LOW_I32_FROM_PTR(u64ptr) LOW_I32_FROM_LONG64_PTR(u64ptr)
@@ -38,69 +35,13 @@
#define DEFAULT_DOUBLE_WIDTH MAX_DOUBLE_ACCURACY_WIDTH
-#if defined(USE_LL)
#define DOUBLE_INFINITE_LONGBITS (0x7FF0000000000000LL)
-#else
-#if defined(USE_L)
-#define DOUBLE_INFINITE_LONGBITS (0x7FF0000000000000L)
-#else
-#define DOUBLE_INFINITE_LONGBITS (0x7FF0000000000000)
-#endif /* USE_L */
-#endif /* USE_LL */
#define DOUBLE_MINIMUM_LONGBITS (0x1)
-#if defined(USE_LL)
#define DOUBLE_MANTISSA_MASK (0x000FFFFFFFFFFFFFLL)
#define DOUBLE_EXPONENT_MASK (0x7FF0000000000000LL)
#define DOUBLE_NORMAL_MASK (0x0010000000000000LL)
-#else
-#if defined(USE_L)
-#define DOUBLE_MANTISSA_MASK (0x000FFFFFFFFFFFFFL)
-#define DOUBLE_EXPONENT_MASK (0x7FF0000000000000L)
-#define DOUBLE_NORMAL_MASK (0x0010000000000000L)
-#else
-#define DOUBLE_MANTISSA_MASK (0x000FFFFFFFFFFFFF)
-#define DOUBLE_EXPONENT_MASK (0x7FF0000000000000)
-#define DOUBLE_NORMAL_MASK (0x0010000000000000)
-#endif /* USE_L */
-#endif /* USE_LL */
-
-/* Keep a count of the number of times we decrement and increment to
- * approximate the double, and attempt to detect the case where we
- * could potentially toggle back and forth between decrementing and
- * incrementing. It is possible for us to be stuck in the loop when
- * incrementing by one or decrementing by one may exceed or stay below
- * the value that we are looking for. In this case, just break out of
- * the loop if we toggle between incrementing and decrementing for more
- * than twice.
- */
-#define INCREMENT_DOUBLE(_x, _decCount, _incCount) \
- { \
- ++DOUBLE_TO_LONGBITS(_x); \
- _incCount++; \
- if( (_incCount > 2) && (_decCount > 2) ) { \
- if( _decCount > _incCount ) { \
- DOUBLE_TO_LONGBITS(_x) += _decCount - _incCount; \
- } else if( _incCount > _decCount ) { \
- DOUBLE_TO_LONGBITS(_x) -= _incCount - _decCount; \
- } \
- break; \
- } \
- }
-#define DECREMENT_DOUBLE(_x, _decCount, _incCount) \
- { \
- --DOUBLE_TO_LONGBITS(_x); \
- _decCount++; \
- if( (_incCount > 2) && (_decCount > 2) ) { \
- if( _decCount > _incCount ) { \
- DOUBLE_TO_LONGBITS(_x) += _decCount - _incCount; \
- } else if( _incCount > _decCount ) { \
- DOUBLE_TO_LONGBITS(_x) -= _incCount - _decCount; \
- } \
- break; \
- } \
- }
#define allocateU64(x, n) if (!((x) = reinterpret_cast<uint64_t*>(malloc((n) * sizeof(uint64_t))))) goto OutOfMemory;
@@ -248,7 +189,6 @@ static jdouble createDouble(JNIEnv* env, const char* s, jint e) {
}
return result;
-
}
static jdouble createDouble1(JNIEnv* env, uint64_t* f, int32_t length, jint e) {
@@ -310,7 +250,6 @@ static jdouble createDouble1(JNIEnv* env, uint64_t* f, int32_t length, jint e) {
first and let it fall to zero if need be. */
if (result == 0.0)
-
DOUBLE_TO_LONGBITS (result) = DOUBLE_MINIMUM_LONGBITS;
return doubleAlgorithm (env, f, length, e, result);
@@ -323,15 +262,6 @@ static jdouble createDouble1(JNIEnv* env, uint64_t* f, int32_t length, jint e) {
* Clinger, Proceedings of the ACM SIGPLAN '90 Conference on
* Programming Language Design and Implementation, June 20-22,
* 1990, pp. 92-101.
- *
- * There is a possibility that the function will end up in an endless
- * loop if the given approximating floating-point number (a very small
- * floating-point whose value is very close to zero) straddles between
- * two approximating integer values. We modified the algorithm slightly
- * to detect the case where it oscillates back and forth between
- * incrementing and decrementing the floating-point approximation. It
- * is currently set such that if the oscillation occurs more than twice
- * then return the original approximation.
*/
static jdouble doubleAlgorithm(JNIEnv* env, uint64_t* f, int32_t length, jint e, jdouble z) {
uint64_t m;
@@ -340,11 +270,10 @@ static jdouble doubleAlgorithm(JNIEnv* env, uint64_t* f, int32_t length, jint e,
uint64_t* y;
uint64_t* D;
uint64_t* D2;
- int32_t xLength, yLength, DLength, D2Length, decApproxCount, incApproxCount;
+ int32_t xLength, yLength, DLength, D2Length;
x = y = D = D2 = 0;
xLength = yLength = DLength = D2Length = 0;
- decApproxCount = incApproxCount = 0;
do
{
@@ -443,12 +372,13 @@ static jdouble doubleAlgorithm(JNIEnv* env, uint64_t* f, int32_t length, jint e,
comparison2 = compareHighPrecision (D2, D2Length, y, yLength);
if (comparison2 < 0)
{
- if (comparison < 0 && m == DOUBLE_NORMAL_MASK)
+ if (comparison < 0 && m == DOUBLE_NORMAL_MASK
+ && DOUBLE_TO_LONGBITS(z) != DOUBLE_NORMAL_MASK)
{
simpleShiftLeftHighPrecision (D2, D2Length, 1);
if (compareHighPrecision (D2, D2Length, y, yLength) > 0)
{
- DECREMENT_DOUBLE (z, decApproxCount, incApproxCount);
+ --DOUBLE_TO_LONGBITS (z);
}
else
{
@@ -466,7 +396,7 @@ static jdouble doubleAlgorithm(JNIEnv* env, uint64_t* f, int32_t length, jint e,
{
if (comparison < 0 && m == DOUBLE_NORMAL_MASK)
{
- DECREMENT_DOUBLE (z, decApproxCount, incApproxCount);
+ --DOUBLE_TO_LONGBITS (z);
}
else
{
@@ -475,24 +405,24 @@ static jdouble doubleAlgorithm(JNIEnv* env, uint64_t* f, int32_t length, jint e,
}
else if (comparison < 0)
{
- DECREMENT_DOUBLE (z, decApproxCount, incApproxCount);
+ --DOUBLE_TO_LONGBITS (z);
break;
}
else
{
- INCREMENT_DOUBLE (z, decApproxCount, incApproxCount);
+ ++DOUBLE_TO_LONGBITS (z);
break;
}
}
else if (comparison < 0)
{
- DECREMENT_DOUBLE (z, decApproxCount, incApproxCount);
+ --DOUBLE_TO_LONGBITS (z);
}
else
{
if (DOUBLE_TO_LONGBITS (z) == DOUBLE_INFINITE_LONGBITS)
break;
- INCREMENT_DOUBLE (z, decApproxCount, incApproxCount);
+ ++DOUBLE_TO_LONGBITS (z);
}
}
while (1);
@@ -547,42 +477,6 @@ static const uint32_t float_tens[] = {
#define FLOAT_EXPONENT_MASK (0x7F800000)
#define FLOAT_NORMAL_MASK (0x00800000)
-/* Keep a count of the number of times we decrement and increment to
- * approximate the double, and attempt to detect the case where we
- * could potentially toggle back and forth between decrementing and
- * incrementing. It is possible for us to be stuck in the loop when
- * incrementing by one or decrementing by one may exceed or stay below
- * the value that we are looking for. In this case, just break out of
- * the loop if we toggle between incrementing and decrementing for more
- * than twice.
- */
-#define INCREMENT_FLOAT(_x, _decCount, _incCount) \
- { \
- ++FLOAT_TO_INTBITS(_x); \
- _incCount++; \
- if( (_incCount > 2) && (_decCount > 2) ) { \
- if( _decCount > _incCount ) { \
- FLOAT_TO_INTBITS(_x) += _decCount - _incCount; \
- } else if( _incCount > _decCount ) { \
- FLOAT_TO_INTBITS(_x) -= _incCount - _decCount; \
- } \
- break; \
- } \
- }
-#define DECREMENT_FLOAT(_x, _decCount, _incCount) \
- { \
- --FLOAT_TO_INTBITS(_x); \
- _decCount++; \
- if( (_incCount > 2) && (_decCount > 2) ) { \
- if( _decCount > _incCount ) { \
- FLOAT_TO_INTBITS(_x) += _decCount - _incCount; \
- } else if( _incCount > _decCount ) { \
- FLOAT_TO_INTBITS(_x) -= _incCount - _decCount; \
- } \
- break; \
- } \
- }
-
static jfloat createFloat(JNIEnv* env, const char* s, jint e) {
/* assumes s is a null terminated string with at least one
* character in it */
@@ -682,7 +576,6 @@ static jfloat createFloat(JNIEnv* env, const char* s, jint e) {
}
return result;
-
}
static jfloat createFloat1 (JNIEnv* env, uint64_t* f, int32_t length, jint e) {
@@ -796,15 +689,6 @@ static jfloat createFloat1 (JNIEnv* env, uint64_t* f, int32_t length, jint e) {
* Clinger, Proceedings of the ACM SIGPLAN '90 Conference on
* Programming Language Design and Implementation, June 20-22,
* 1990, pp. 92-101.
- *
- * There is a possibility that the function will end up in an endless
- * loop if the given approximating floating-point number (a very small
- * floating-point whose value is very close to zero) straddles between
- * two approximating integer values. We modified the algorithm slightly
- * to detect the case where it oscillates back and forth between
- * incrementing and decrementing the floating-point approximation. It
- * is currently set such that if the oscillation occurs more than twice
- * then return the original approximation.
*/
static jfloat floatAlgorithm(JNIEnv* env, uint64_t* f, int32_t length, jint e, jfloat z) {
uint64_t m;
@@ -814,11 +698,9 @@ static jfloat floatAlgorithm(JNIEnv* env, uint64_t* f, int32_t length, jint e, j
uint64_t* D;
uint64_t* D2;
int32_t xLength, yLength, DLength, D2Length;
- int32_t decApproxCount, incApproxCount;
x = y = D = D2 = 0;
xLength = yLength = DLength = D2Length = 0;
- decApproxCount = incApproxCount = 0;
do
{
@@ -917,12 +799,13 @@ static jfloat floatAlgorithm(JNIEnv* env, uint64_t* f, int32_t length, jint e, j
comparison2 = compareHighPrecision (D2, D2Length, y, yLength);
if (comparison2 < 0)
{
- if (comparison < 0 && m == FLOAT_NORMAL_MASK)
+ if (comparison < 0 && m == FLOAT_NORMAL_MASK
+ && FLOAT_TO_INTBITS(z) != FLOAT_NORMAL_MASK)
{
simpleShiftLeftHighPrecision (D2, D2Length, 1);
if (compareHighPrecision (D2, D2Length, y, yLength) > 0)
{
- DECREMENT_FLOAT (z, decApproxCount, incApproxCount);
+ --FLOAT_TO_INTBITS (z);
}
else
{
@@ -940,7 +823,7 @@ static jfloat floatAlgorithm(JNIEnv* env, uint64_t* f, int32_t length, jint e, j
{
if (comparison < 0 && m == FLOAT_NORMAL_MASK)
{
- DECREMENT_FLOAT (z, decApproxCount, incApproxCount);
+ --FLOAT_TO_INTBITS (z);
}
else
{
@@ -949,24 +832,24 @@ static jfloat floatAlgorithm(JNIEnv* env, uint64_t* f, int32_t length, jint e, j
}
else if (comparison < 0)
{
- DECREMENT_FLOAT (z, decApproxCount, incApproxCount);
+ --FLOAT_TO_INTBITS (z);
break;
}
else
{
- INCREMENT_FLOAT (z, decApproxCount, incApproxCount);
+ ++FLOAT_TO_INTBITS (z);
break;
}
}
else if (comparison < 0)
{
- DECREMENT_FLOAT (z, decApproxCount, incApproxCount);
+ --FLOAT_TO_INTBITS (z);
}
else
{
if (FLOAT_TO_INTBITS (z) == FLOAT_EXPONENT_MASK)
break;
- INCREMENT_FLOAT (z, decApproxCount, incApproxCount);
+ ++FLOAT_TO_INTBITS (z);
}
}
while (1);
diff --git a/luni/src/main/native/java_lang_System.cpp b/luni/src/main/native/java_lang_System.cpp
index 944c0c3..306adab 100644
--- a/luni/src/main/native/java_lang_System.cpp
+++ b/luni/src/main/native/java_lang_System.cpp
@@ -84,7 +84,11 @@ static jobjectArray System_specialProperties(JNIEnv* env, jclass) {
properties.push_back(std::string("user.dir=") + getcwd(path, sizeof(path)));
properties.push_back("android.zlib.version=" ZLIB_VERSION);
+#if defined(OPENSSL_IS_BORINGSSL)
+ properties.push_back("android.openssl.version=BoringSSL");
+#else
properties.push_back("android.openssl.version=" OPENSSL_VERSION_TEXT);
+#endif
const char* library_path = getenv("LD_LIBRARY_PATH");
#if defined(HAVE_ANDROID_OS)
@@ -109,33 +113,20 @@ static jlong System_currentTimeMillis(JNIEnv*, jclass) {
}
static jlong System_nanoTime(JNIEnv*, jclass) {
-#if defined(HAVE_POSIX_CLOCKS)
+#if defined(__linux__)
timespec now;
clock_gettime(CLOCK_MONOTONIC, &now);
return now.tv_sec * 1000000000LL + now.tv_nsec;
-#else
+#else // __APPLE__
timeval now;
gettimeofday(&now, NULL);
return static_cast<jlong>(now.tv_sec) * 1000000000LL + now.tv_usec * 1000LL;
#endif
}
-static jstring System_mapLibraryName(JNIEnv* env, jclass, jstring javaName) {
- ScopedUtfChars name(env, javaName);
- if (name.c_str() == NULL) {
- return NULL;
- }
- char* mappedName = NULL;
- asprintf(&mappedName, OS_SHARED_LIB_FORMAT_STR, name.c_str());
- jstring result = env->NewStringUTF(mappedName);
- free(mappedName);
- return result;
-}
-
static JNINativeMethod gMethods[] = {
NATIVE_METHOD(System, currentTimeMillis, "!()J"),
NATIVE_METHOD(System, log, "(CLjava/lang/String;Ljava/lang/Throwable;)V"),
- NATIVE_METHOD(System, mapLibraryName, "(Ljava/lang/String;)Ljava/lang/String;"),
NATIVE_METHOD(System, nanoTime, "!()J"),
NATIVE_METHOD(System, setFieldImpl, "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/Object;)V"),
NATIVE_METHOD(System, specialProperties, "()[Ljava/lang/String;"),
diff --git a/luni/src/main/native/java_math_NativeBN.cpp b/luni/src/main/native/java_math_NativeBN.cpp
index be87ea6..7e77e23 100644
--- a/luni/src/main/native/java_math_NativeBN.cpp
+++ b/luni/src/main/native/java_math_NativeBN.cpp
@@ -21,19 +21,31 @@
#include "JniException.h"
#include "ScopedPrimitiveArray.h"
#include "ScopedUtfChars.h"
-#include "UniquePtr.h"
#include "jni.h"
#include <openssl/bn.h>
#include <openssl/crypto.h>
#include <openssl/err.h>
#include <stdio.h>
+#include <memory>
+
+#if defined(OPENSSL_IS_BORINGSSL)
+/* BoringSSL no longer exports |bn_check_top|. */
+static void bn_check_top(const BIGNUM* bn) {
+ /* This asserts that |bn->top| (which contains the number of elements of
+ * |bn->d| that are valid) is minimal. In other words, that there aren't
+ * superfluous zeros. */
+ if (bn != NULL && bn->top != 0 && bn->d[bn->top-1] == 0) {
+ abort();
+ }
+}
+#endif
struct BN_CTX_Deleter {
void operator()(BN_CTX* p) const {
BN_CTX_free(p);
}
};
-typedef UniquePtr<BN_CTX, BN_CTX_Deleter> Unique_BN_CTX;
+typedef std::unique_ptr<BN_CTX, BN_CTX_Deleter> Unique_BN_CTX;
static BIGNUM* toBigNum(jlong address) {
return reinterpret_cast<BIGNUM*>(static_cast<uintptr_t>(address));
@@ -109,28 +121,32 @@ static void NativeBN_BN_copy(JNIEnv* env, jclass, jlong to, jlong from) {
}
static void NativeBN_putULongInt(JNIEnv* env, jclass, jlong a0, jlong java_dw, jboolean neg) {
- if (!oneValidHandle(env, a0)) return;
+ if (!oneValidHandle(env, a0)) return;
- uint64_t dw = java_dw;
+ uint64_t dw = java_dw;
+ BIGNUM* a = toBigNum(a0);
+ int ok;
- // cf. litEndInts2bn:
- BIGNUM* a = toBigNum(a0);
- bn_check_top(a);
- if (bn_wexpand(a, 8/BN_BYTES) != NULL) {
-#ifdef __LP64__
+ static_assert(sizeof(dw) == sizeof(BN_ULONG) ||
+ sizeof(dw) == 2*sizeof(BN_ULONG), "Unknown BN configuration");
+
+ if (sizeof(dw) == sizeof(BN_ULONG)) {
+ ok = BN_set_word(a, dw);
+ } else if (sizeof(dw) == 2 * sizeof(BN_ULONG)) {
+ ok = (bn_wexpand(a, 2) != NULL);
+ if (ok) {
a->d[0] = dw;
-#else
- unsigned int hi = dw >> 32; // This shifts without sign extension.
- int lo = (int)dw; // This truncates implicitly.
- a->d[0] = lo;
- a->d[1] = hi;
-#endif
- a->top = 8 / BN_BYTES;
- a->neg = neg;
+ a->d[1] = dw >> 32;
+ a->top = 2;
bn_correct_top(a);
- } else {
- throwExceptionIfNecessary(env);
}
+ }
+
+ BN_set_negative(a, neg);
+
+ if (!ok) {
+ throwExceptionIfNecessary(env);
+ }
}
static void NativeBN_putLongInt(JNIEnv* env, jclass cls, jlong a, jlong dw) {
@@ -240,25 +256,25 @@ static void negBigEndianBytes2bn(JNIEnv*, jclass, const unsigned char* bytes, in
bn_check_top(ret);
// FIXME: assert bytesLen > 0
- int wLen = (bytesLen + BN_BYTES - 1) / BN_BYTES;
+ int wLen = (bytesLen + sizeof(BN_ULONG) - 1) / sizeof(BN_ULONG);
int firstNonzeroDigit = -2;
if (bn_wexpand(ret, wLen) != NULL) {
BN_ULONG* d = ret->d;
BN_ULONG di;
ret->top = wLen;
- int highBytes = bytesLen % BN_BYTES;
+ int highBytes = bytesLen % sizeof(BN_ULONG);
int k = bytesLen;
// Put bytes to the int array starting from the end of the byte array
int i = 0;
while (k > highBytes) {
- k -= BN_BYTES;
+ k -= sizeof(BN_ULONG);
di = BYTES2ULONG(bytes, k);
if (di != 0) {
d[i] = -di;
firstNonzeroDigit = i;
i++;
while (k > highBytes) {
- k -= BN_BYTES;
+ k -= sizeof(BN_ULONG);
d[i] = ~BYTES2ULONG(bytes, k);
i++;
}
@@ -394,7 +410,7 @@ static jintArray NativeBN_bn2litEndInts(JNIEnv* env, jclass, jlong a0) {
if (wLen == 0) {
return NULL;
}
- jintArray result = env->NewIntArray(wLen * BN_BYTES/sizeof(unsigned int));
+ jintArray result = env->NewIntArray(wLen * sizeof(BN_ULONG)/sizeof(unsigned int));
if (result == NULL) {
return NULL;
}
@@ -445,7 +461,7 @@ static int NativeBN_bitLength(JNIEnv* env, jclass, jlong a0) {
do { i--; } while (!((i < 0) || (d[i] != 0)));
if (i < 0) msd--; // Only if all lower significant digits are 0 we decrement the most significant one.
}
- return (wLen - 1) * BN_BYTES * 8 + BN_num_bits_word(msd);
+ return (wLen - 1) * sizeof(BN_ULONG) * 8 + BN_num_bits_word(msd);
}
static jboolean NativeBN_BN_is_bit_set(JNIEnv* env, jclass, jlong a, int n) {
diff --git a/luni/src/main/native/java_nio_charset_Charsets.cpp b/luni/src/main/native/java_nio_charset_Charsets.cpp
deleted file mode 100644
index a49ba22..0000000
--- a/luni/src/main/native/java_nio_charset_Charsets.cpp
+++ /dev/null
@@ -1,250 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define LOG_TAG "String"
-
-#include "JNIHelp.h"
-#include "JniConstants.h"
-#include "ScopedPrimitiveArray.h"
-#include "jni.h"
-#include "unicode/utf16.h"
-
-#include <string.h>
-
-/**
- * Approximates java.lang.UnsafeByteSequence so we don't have to pay the cost of calling back into
- * Java when converting a char[] to a UTF-8 byte[]. This lets us have UTF-8 conversions slightly
- * faster than ICU for large char[]s without paying for the NIO overhead with small char[]s.
- *
- * We could avoid this by keeping the UTF-8 bytes on the native heap until we're done and only
- * creating a byte[] on the Java heap when we know how big it needs to be, but one shouldn't lie
- * to the garbage collector (nor hide potentially large allocations from it).
- *
- * Because a call to append might require an allocation, it might fail. Callers should always
- * check the return value of append.
- */
-class NativeUnsafeByteSequence {
-public:
- NativeUnsafeByteSequence(JNIEnv* env)
- : mEnv(env), mJavaArray(NULL), mRawArray(NULL), mSize(-1), mOffset(0)
- {
- }
-
- ~NativeUnsafeByteSequence() {
- // Release our pointer to the raw array, copying changes back to the Java heap.
- if (mRawArray != NULL) {
- mEnv->ReleaseByteArrayElements(mJavaArray, mRawArray, 0);
- }
- }
-
- bool append(jbyte b) {
- if (mOffset == mSize && !resize(mSize * 2)) {
- return false;
- }
- mRawArray[mOffset++] = b;
- return true;
- }
-
- bool resize(int newSize) {
- if (newSize == mSize) {
- return true;
- }
-
- // Allocate a new array.
- jbyteArray newJavaArray = mEnv->NewByteArray(newSize);
- if (newJavaArray == NULL) {
- return false;
- }
- jbyte* newRawArray = mEnv->GetByteArrayElements(newJavaArray, NULL);
- if (newRawArray == NULL) {
- return false;
- }
-
- // Copy data out of the old array and then let go of it.
- // Note that we may be trimming the array.
- if (mRawArray != NULL) {
- memcpy(newRawArray, mRawArray, mOffset);
- mEnv->ReleaseByteArrayElements(mJavaArray, mRawArray, JNI_ABORT);
- mEnv->DeleteLocalRef(mJavaArray);
- }
-
- // Point ourselves at the new array.
- mJavaArray = newJavaArray;
- mRawArray = newRawArray;
- mSize = newSize;
- return true;
- }
-
- jbyteArray toByteArray() {
- // Trim any unused space, if necessary.
- bool okay = resize(mOffset);
- return okay ? mJavaArray : NULL;
- }
-
-private:
- JNIEnv* mEnv;
- jbyteArray mJavaArray;
- jbyte* mRawArray;
- jint mSize;
- jint mOffset;
-
- // Disallow copy and assignment.
- NativeUnsafeByteSequence(const NativeUnsafeByteSequence&);
- void operator=(const NativeUnsafeByteSequence&);
-};
-
-static void Charsets_asciiBytesToChars(JNIEnv* env, jclass, jbyteArray javaBytes, jint offset, jint length, jcharArray javaChars) {
- ScopedByteArrayRO bytes(env, javaBytes);
- if (bytes.get() == NULL) {
- return;
- }
- ScopedCharArrayRW chars(env, javaChars);
- if (chars.get() == NULL) {
- return;
- }
-
- const jbyte* src = &bytes[offset];
- jchar* dst = &chars[0];
- static const jchar REPLACEMENT_CHAR = 0xfffd;
- for (int i = length - 1; i >= 0; --i) {
- jchar ch = static_cast<jchar>(*src++ & 0xff);
- *dst++ = (ch <= 0x7f) ? ch : REPLACEMENT_CHAR;
- }
-}
-
-static void Charsets_isoLatin1BytesToChars(JNIEnv* env, jclass, jbyteArray javaBytes, jint offset, jint length, jcharArray javaChars) {
- ScopedByteArrayRO bytes(env, javaBytes);
- if (bytes.get() == NULL) {
- return;
- }
- ScopedCharArrayRW chars(env, javaChars);
- if (chars.get() == NULL) {
- return;
- }
-
- const jbyte* src = &bytes[offset];
- jchar* dst = &chars[0];
- for (int i = length - 1; i >= 0; --i) {
- *dst++ = static_cast<jchar>(*src++ & 0xff);
- }
-}
-
-/**
- * Translates the given characters to US-ASCII or ISO-8859-1 bytes, using the fact that
- * Unicode code points between U+0000 and U+007f inclusive are identical to US-ASCII, while
- * U+0000 to U+00ff inclusive are identical to ISO-8859-1.
- */
-static jbyteArray charsToBytes(JNIEnv* env, jcharArray javaChars, jint offset, jint length, jchar maxValidChar) {
- ScopedCharArrayRO chars(env, javaChars);
- if (chars.get() == NULL) {
- return NULL;
- }
-
- jbyteArray javaBytes = env->NewByteArray(length);
- ScopedByteArrayRW bytes(env, javaBytes);
- if (bytes.get() == NULL) {
- return NULL;
- }
-
- const jchar* src = &chars[offset];
- jbyte* dst = &bytes[0];
- for (int i = length - 1; i >= 0; --i) {
- jchar ch = *src++;
- if (ch > maxValidChar) {
- ch = '?';
- }
- *dst++ = static_cast<jbyte>(ch);
- }
-
- return javaBytes;
-}
-
-static jbyteArray Charsets_toAsciiBytes(JNIEnv* env, jclass, jcharArray javaChars, jint offset, jint length) {
- return charsToBytes(env, javaChars, offset, length, 0x7f);
-}
-
-static jbyteArray Charsets_toIsoLatin1Bytes(JNIEnv* env, jclass, jcharArray javaChars, jint offset, jint length) {
- return charsToBytes(env, javaChars, offset, length, 0xff);
-}
-
-static jbyteArray Charsets_toUtf8Bytes(JNIEnv* env, jclass, jcharArray javaChars, jint offset, jint length) {
- ScopedCharArrayRO chars(env, javaChars);
- if (chars.get() == NULL) {
- return NULL;
- }
-
- NativeUnsafeByteSequence out(env);
- if (!out.resize(length)) {
- return NULL;
- }
-
- const int end = offset + length;
- for (int i = offset; i < end; ++i) {
- jint ch = chars[i];
- if (ch < 0x80) {
- // One byte.
- if (!out.append(ch)) {
- return NULL;
- }
- } else if (ch < 0x800) {
- // Two bytes.
- if (!out.append((ch >> 6) | 0xc0) || !out.append((ch & 0x3f) | 0x80)) {
- return NULL;
- }
- } else if (U16_IS_SURROGATE(ch)) {
- // A supplementary character.
- jchar high = (jchar) ch;
- jchar low = (i + 1 != end) ? chars[i + 1] : 0;
- if (!U16_IS_SURROGATE_LEAD(high) || !U16_IS_SURROGATE_TRAIL(low)) {
- if (!out.append('?')) {
- return NULL;
- }
- continue;
- }
- // Now we know we have a *valid* surrogate pair, we can consume the low surrogate.
- ++i;
- ch = U16_GET_SUPPLEMENTARY(high, low);
- // Four bytes.
- jbyte b1 = (ch >> 18) | 0xf0;
- jbyte b2 = ((ch >> 12) & 0x3f) | 0x80;
- jbyte b3 = ((ch >> 6) & 0x3f) | 0x80;
- jbyte b4 = (ch & 0x3f) | 0x80;
- if (!out.append(b1) || !out.append(b2) || !out.append(b3) || !out.append(b4)) {
- return NULL;
- }
- } else {
- // Three bytes.
- jbyte b1 = (ch >> 12) | 0xe0;
- jbyte b2 = ((ch >> 6) & 0x3f) | 0x80;
- jbyte b3 = (ch & 0x3f) | 0x80;
- if (!out.append(b1) || !out.append(b2) || !out.append(b3)) {
- return NULL;
- }
- }
- }
- return out.toByteArray();
-}
-
-static JNINativeMethod gMethods[] = {
- NATIVE_METHOD(Charsets, asciiBytesToChars, "([BII[C)V"),
- NATIVE_METHOD(Charsets, isoLatin1BytesToChars, "([BII[C)V"),
- NATIVE_METHOD(Charsets, toAsciiBytes, "([CII)[B"),
- NATIVE_METHOD(Charsets, toIsoLatin1Bytes, "([CII)[B"),
- NATIVE_METHOD(Charsets, toUtf8Bytes, "([CII)[B"),
-};
-void register_java_nio_charset_Charsets(JNIEnv* env) {
- jniRegisterNativeMethods(env, "java/nio/charset/Charsets", gMethods, NELEM(gMethods));
-}
diff --git a/luni/src/main/native/java_text_Bidi.cpp b/luni/src/main/native/java_text_Bidi.cpp
index d9ef35d..6a3e751 100644
--- a/luni/src/main/native/java_text_Bidi.cpp
+++ b/luni/src/main/native/java_text_Bidi.cpp
@@ -22,14 +22,14 @@
#include "JniConstants.h"
#include "JniException.h"
#include "ScopedPrimitiveArray.h"
-#include "UniquePtr.h"
#include "unicode/ubidi.h"
#include <stdlib.h>
#include <string.h>
+#include <memory>
struct BiDiData {
- BiDiData(UBiDi* biDi) : mBiDi(biDi), mEmbeddingLevels(NULL) {
+ BiDiData(UBiDi* biDi) : mBiDi(biDi) {
}
~BiDiData() {
@@ -50,7 +50,7 @@ struct BiDiData {
private:
UBiDi* mBiDi;
- UniquePtr<jbyte[]> mEmbeddingLevels;
+ std::unique_ptr<jbyte[]> mEmbeddingLevels;
// Disallow copy and assignment.
BiDiData(const BiDiData&);
@@ -98,7 +98,7 @@ static jlong Bidi_ubidi_setLine(JNIEnv* env, jclass, jlong ptr, jint start, jint
if (maybeThrowIcuException(env, "ubidi_openSized", status)) {
return 0;
}
- UniquePtr<BiDiData> lineData(new BiDiData(sized));
+ std::unique_ptr<BiDiData> lineData(new BiDiData(sized));
ubidi_setLine(uBiDi(ptr), start, limit, lineData->uBiDi(), &status);
maybeThrowIcuException(env, "ubidi_setLine", status);
return reinterpret_cast<uintptr_t>(lineData.release());
@@ -168,7 +168,7 @@ static jintArray Bidi_ubidi_reorderVisual(JNIEnv* env, jclass, jbyteArray javaLe
const UBiDiLevel* levels = reinterpret_cast<const UBiDiLevel*>(levelBytes.get());
- UniquePtr<int[]> indexMap(new int[length]);
+ std::unique_ptr<int[]> indexMap(new int[length]);
ubidi_reorderVisual(levels, length, &indexMap[0]);
jintArray result = env->NewIntArray(length);
diff --git a/luni/src/main/native/java_util_jar_StrictJarFile.cpp b/luni/src/main/native/java_util_jar_StrictJarFile.cpp
index efcc74c..03d0784 100644
--- a/luni/src/main/native/java_util_jar_StrictJarFile.cpp
+++ b/luni/src/main/native/java_util_jar_StrictJarFile.cpp
@@ -17,49 +17,26 @@
#define LOG_TAG "StrictJarFile"
+#include <memory>
#include <string>
#include "JNIHelp.h"
#include "JniConstants.h"
#include "ScopedLocalRef.h"
#include "ScopedUtfChars.h"
-#include "UniquePtr.h"
#include "jni.h"
#include "ziparchive/zip_archive.h"
#include "cutils/log.h"
+// The method ID for ZipEntry.<init>(String,String,JJJIII[BJJ)
+static jmethodID zipEntryCtor;
+
static void throwIoException(JNIEnv* env, const int32_t errorCode) {
jniThrowException(env, "java/io/IOException", ErrorCodeString(errorCode));
}
-// Constructs a string out of |name| with the default charset (UTF-8 on android).
-// We prefer this to JNI's NewStringUTF because the string constructor will
-// replace unmappable and malformed bytes instead of throwing. See b/18584205
-//
-// Returns |NULL| iff. we couldn't allocate the string object or its constructor
-// arguments.
-//
-// TODO: switch back to NewStringUTF after libziparchive is modified to reject
-// files whose names aren't valid UTF-8.
-static jobject constructString(JNIEnv* env, const char* name, const uint16_t nameLength) {
- jbyteArray javaNameBytes = env->NewByteArray(nameLength);
- if (javaNameBytes == NULL) {
- return NULL;
- }
- env->SetByteArrayRegion(javaNameBytes, 0, nameLength, reinterpret_cast<const jbyte*>(name));
-
- ScopedLocalRef<jclass> stringClass(env, env->FindClass("java/lang/String"));
- const jmethodID stringCtor = env->GetMethodID(stringClass.get(), "<init>", "([B)V");
- return env->NewObject(stringClass.get(), stringCtor, javaNameBytes);
-}
-
-static jobject newZipEntry(JNIEnv* env, const ZipEntry& entry, const jobject entryName,
- const uint16_t nameLength) {
- ScopedLocalRef<jclass> zipEntryClass(env, env->FindClass("java/util/zip/ZipEntry"));
- const jmethodID zipEntryCtor = env->GetMethodID(zipEntryClass.get(), "<init>",
- "(Ljava/lang/String;Ljava/lang/String;JJJIII[BIJJ)V");
-
- return env->NewObject(zipEntryClass.get(),
+static jobject newZipEntry(JNIEnv* env, const ZipEntry& entry, jstring entryName) {
+ return env->NewObject(JniConstants::zipEntryClass,
zipEntryCtor,
entryName,
NULL, // comment
@@ -70,16 +47,10 @@ static jobject newZipEntry(JNIEnv* env, const ZipEntry& entry, const jobject ent
static_cast<jint>(0), // time
static_cast<jint>(0), // modData
NULL, // byte[] extra
- static_cast<jint>(nameLength),
static_cast<jlong>(-1), // local header offset
static_cast<jlong>(entry.offset));
}
-static jobject newZipEntry(JNIEnv* env, const ZipEntry& entry, const char* name,
- const uint16_t nameLength) {
- return newZipEntry(env, entry, constructString(env, name, nameLength), nameLength);
-}
-
static jlong StrictJarFile_nativeOpenJarFile(JNIEnv* env, jobject, jstring fileName) {
ScopedUtfChars fileChars(env, fileName);
if (fileChars.c_str() == NULL) {
@@ -89,6 +60,7 @@ static jlong StrictJarFile_nativeOpenJarFile(JNIEnv* env, jobject, jstring fileN
ZipArchiveHandle handle;
int32_t error = OpenArchive(fileChars.c_str(), &handle);
if (error) {
+ CloseArchive(handle);
throwIoException(env, error);
return static_cast<jlong>(-1);
}
@@ -98,25 +70,20 @@ static jlong StrictJarFile_nativeOpenJarFile(JNIEnv* env, jobject, jstring fileN
class IterationHandle {
public:
- IterationHandle(const char* prefix) :
- cookie_(NULL), prefix_(strdup(prefix)) {
+ IterationHandle() :
+ cookie_(NULL) {
}
void** CookieAddress() {
return &cookie_;
}
- const char* Prefix() const {
- return prefix_;
- }
-
~IterationHandle() {
- free(prefix_);
+ EndIteration(cookie_);
}
private:
void* cookie_;
- char* prefix_;
};
@@ -127,14 +94,15 @@ static jlong StrictJarFile_nativeStartIteration(JNIEnv* env, jobject, jlong nati
return static_cast<jlong>(-1);
}
- IterationHandle* handle = new IterationHandle(prefixChars.c_str());
+ IterationHandle* handle = new IterationHandle();
int32_t error = 0;
if (prefixChars.size() == 0) {
error = StartIteration(reinterpret_cast<ZipArchiveHandle>(nativeHandle),
handle->CookieAddress(), NULL);
} else {
+ ZipEntryName entry_name(prefixChars.c_str());
error = StartIteration(reinterpret_cast<ZipArchiveHandle>(nativeHandle),
- handle->CookieAddress(), handle->Prefix());
+ handle->CookieAddress(), &entry_name);
}
if (error) {
@@ -156,11 +124,12 @@ static jobject StrictJarFile_nativeNextEntry(JNIEnv* env, jobject, jlong iterati
return NULL;
}
- UniquePtr<char[]> entryNameCString(new char[entryName.name_length + 1]);
+ std::unique_ptr<char[]> entryNameCString(new char[entryName.name_length + 1]);
memcpy(entryNameCString.get(), entryName.name, entryName.name_length);
entryNameCString[entryName.name_length] = '\0';
+ ScopedLocalRef<jstring> entryNameString(env, env->NewStringUTF(entryNameCString.get()));
- return newZipEntry(env, data, entryNameCString.get(), entryName.name_length);
+ return newZipEntry(env, data, entryNameString.get());
}
static jobject StrictJarFile_nativeFindEntry(JNIEnv* env, jobject, jlong nativeHandle,
@@ -172,12 +141,12 @@ static jobject StrictJarFile_nativeFindEntry(JNIEnv* env, jobject, jlong nativeH
ZipEntry data;
const int32_t error = FindEntry(reinterpret_cast<ZipArchiveHandle>(nativeHandle),
- entryNameChars.c_str(), &data);
+ ZipEntryName(entryNameChars.c_str()), &data);
if (error) {
return NULL;
}
- return newZipEntry(env, data, entryName, entryNameChars.size());
+ return newZipEntry(env, data, entryName);
}
static void StrictJarFile_nativeClose(JNIEnv*, jobject, jlong nativeHandle) {
@@ -194,4 +163,8 @@ static JNINativeMethod gMethods[] = {
void register_java_util_jar_StrictJarFile(JNIEnv* env) {
jniRegisterNativeMethods(env, "java/util/jar/StrictJarFile", gMethods, NELEM(gMethods));
+
+ zipEntryCtor = env->GetMethodID(JniConstants::zipEntryClass, "<init>",
+ "(Ljava/lang/String;Ljava/lang/String;JJJIII[BJJ)V");
+ LOG_ALWAYS_FATAL_IF(zipEntryCtor == NULL, "Unable to find ZipEntry.<init>");
}
diff --git a/luni/src/main/native/java_util_regex_Matcher.cpp b/luni/src/main/native/java_util_regex_Matcher.cpp
index 2e5259e..35d014c 100644
--- a/luni/src/main/native/java_util_regex_Matcher.cpp
+++ b/luni/src/main/native/java_util_regex_Matcher.cpp
@@ -23,15 +23,14 @@
#include "JniConstants.h"
#include "JniException.h"
#include "ScopedPrimitiveArray.h"
-#include "UniquePtr.h"
#include "jni.h"
#include "unicode/parseerr.h"
#include "unicode/regex.h"
// ICU documentation: http://icu-project.org/apiref/icu4c/classRegexMatcher.html
-static RegexMatcher* toRegexMatcher(jlong address) {
- return reinterpret_cast<RegexMatcher*>(static_cast<uintptr_t>(address));
+static icu::RegexMatcher* toRegexMatcher(jlong address) {
+ return reinterpret_cast<icu::RegexMatcher*>(static_cast<uintptr_t>(address));
}
/**
@@ -75,7 +74,7 @@ public:
maybeThrowIcuException(mEnv, "utext_close", mStatus);
}
- RegexMatcher* operator->() {
+ icu::RegexMatcher* operator->() {
return mMatcher;
}
@@ -107,7 +106,7 @@ private:
JNIEnv* mEnv;
jstring mJavaInput;
- RegexMatcher* mMatcher;
+ icu::RegexMatcher* mMatcher;
const jchar* mChars;
UErrorCode mStatus;
UText* mUText;
@@ -171,9 +170,9 @@ static jint Matcher_matchesImpl(JNIEnv* env, jclass, jlong addr, jstring javaTex
}
static jlong Matcher_openImpl(JNIEnv* env, jclass, jlong patternAddr) {
- RegexPattern* pattern = reinterpret_cast<RegexPattern*>(static_cast<uintptr_t>(patternAddr));
+ icu::RegexPattern* pattern = reinterpret_cast<icu::RegexPattern*>(static_cast<uintptr_t>(patternAddr));
UErrorCode status = U_ZERO_ERROR;
- RegexMatcher* result = pattern->matcher(status);
+ icu::RegexMatcher* result = pattern->matcher(status);
maybeThrowIcuException(env, "RegexPattern::matcher", status);
return reinterpret_cast<uintptr_t>(result);
}
diff --git a/luni/src/main/native/java_util_regex_Pattern.cpp b/luni/src/main/native/java_util_regex_Pattern.cpp
index 1a99d0a..f2c07dc 100644
--- a/luni/src/main/native/java_util_regex_Pattern.cpp
+++ b/luni/src/main/native/java_util_regex_Pattern.cpp
@@ -27,8 +27,8 @@
// ICU documentation: http://icu-project.org/apiref/icu4c/classRegexPattern.html
-static RegexPattern* toRegexPattern(jlong addr) {
- return reinterpret_cast<RegexPattern*>(static_cast<uintptr_t>(addr));
+static icu::RegexPattern* toRegexPattern(jlong addr) {
+ return reinterpret_cast<icu::RegexPattern*>(static_cast<uintptr_t>(addr));
}
static const char* regexDetailMessage(UErrorCode status) {
@@ -86,8 +86,8 @@ static jlong Pattern_compileImpl(JNIEnv* env, jclass, jstring javaRegex, jint fl
if (!regex.valid()) {
return 0;
}
- UnicodeString& regexString(regex.unicodeString());
- RegexPattern* result = RegexPattern::compile(regexString, flags, error, status);
+ icu::UnicodeString& regexString(regex.unicodeString());
+ icu::RegexPattern* result = icu::RegexPattern::compile(regexString, flags, error, status);
if (!U_SUCCESS(status)) {
throwPatternSyntaxException(env, status, javaRegex, error);
}
diff --git a/luni/src/main/native/java_util_zip_Deflater.cpp b/luni/src/main/native/java_util_zip_Deflater.cpp
index 1afd36e..d963824 100644
--- a/luni/src/main/native/java_util_zip_Deflater.cpp
+++ b/luni/src/main/native/java_util_zip_Deflater.cpp
@@ -28,11 +28,11 @@ static void Deflater_setDictionaryImpl(JNIEnv* env, jobject, jbyteArray dict, in
}
static jlong Deflater_getTotalInImpl(JNIEnv*, jobject, jlong handle) {
- return toNativeZipStream(handle)->stream.total_in;
+ return toNativeZipStream(handle)->totalIn;
}
static jlong Deflater_getTotalOutImpl(JNIEnv*, jobject, jlong handle) {
- return toNativeZipStream(handle)->stream.total_out;
+ return toNativeZipStream(handle)->totalOut;
}
static jint Deflater_getAdlerImpl(JNIEnv*, jobject, jlong handle) {
@@ -40,7 +40,7 @@ static jint Deflater_getAdlerImpl(JNIEnv*, jobject, jlong handle) {
}
static jlong Deflater_createStream(JNIEnv * env, jobject, jint level, jint strategy, jboolean noHeader) {
- UniquePtr<NativeZipStream> jstream(new NativeZipStream);
+ std::unique_ptr<NativeZipStream> jstream(new NativeZipStream);
if (jstream.get() == NULL) {
jniThrowOutOfMemoryError(env, NULL);
return -1;
@@ -101,6 +101,9 @@ static jint Deflater_deflateImpl(JNIEnv* env, jobject recv, jbyteArray buf, int
jint bytesRead = stream->stream.next_in - initialNextIn;
jint bytesWritten = stream->stream.next_out - initialNextOut;
+ stream->totalIn += bytesRead;
+ stream->totalOut += bytesWritten;
+
static jfieldID inReadField = env->GetFieldID(JniConstants::deflaterClass, "inRead", "I");
jint inReadValue = env->GetIntField(recv, inReadField);
inReadValue += bytesRead;
@@ -116,6 +119,8 @@ static void Deflater_endImpl(JNIEnv*, jobject, jlong handle) {
static void Deflater_resetImpl(JNIEnv* env, jobject, jlong handle) {
NativeZipStream* stream = toNativeZipStream(handle);
+ stream->totalIn = 0;
+ stream->totalOut = 0;
int err = deflateReset(&stream->stream);
if (err != Z_OK) {
throwExceptionForZlibError(env, "java/lang/IllegalArgumentException", err, stream);
diff --git a/luni/src/main/native/java_util_zip_Inflater.cpp b/luni/src/main/native/java_util_zip_Inflater.cpp
index ca3ee09..f0878ff 100644
--- a/luni/src/main/native/java_util_zip_Inflater.cpp
+++ b/luni/src/main/native/java_util_zip_Inflater.cpp
@@ -25,7 +25,7 @@
#include <errno.h>
static jlong Inflater_createStream(JNIEnv* env, jobject, jboolean noHeader) {
- UniquePtr<NativeZipStream> jstream(new NativeZipStream);
+ std::unique_ptr<NativeZipStream> jstream(new NativeZipStream);
if (jstream.get() == NULL) {
jniThrowOutOfMemoryError(env, NULL);
return -1;
@@ -122,6 +122,9 @@ static jint Inflater_inflateImpl(JNIEnv* env, jobject recv, jbyteArray buf, int
jint bytesRead = stream->stream.next_in - initialNextIn;
jint bytesWritten = stream->stream.next_out - initialNextOut;
+ stream->totalIn += bytesRead;
+ stream->totalOut += bytesWritten;
+
static jfieldID inReadField = env->GetFieldID(JniConstants::inflaterClass, "inRead", "I");
jint inReadValue = env->GetIntField(recv, inReadField);
inReadValue += bytesRead;
@@ -145,6 +148,8 @@ static void Inflater_setDictionaryImpl(JNIEnv* env, jobject, jbyteArray dict, in
static void Inflater_resetImpl(JNIEnv* env, jobject, jlong handle) {
NativeZipStream* stream = toNativeZipStream(handle);
+ stream->totalIn = 0;
+ stream->totalOut = 0;
int err = inflateReset(&stream->stream);
if (err != Z_OK) {
throwExceptionForZlibError(env, "java/lang/IllegalArgumentException", err, stream);
@@ -152,11 +157,11 @@ static void Inflater_resetImpl(JNIEnv* env, jobject, jlong handle) {
}
static jlong Inflater_getTotalOutImpl(JNIEnv*, jobject, jlong handle) {
- return toNativeZipStream(handle)->stream.total_out;
+ return toNativeZipStream(handle)->totalOut;
}
static jlong Inflater_getTotalInImpl(JNIEnv*, jobject, jlong handle) {
- return toNativeZipStream(handle)->stream.total_in;
+ return toNativeZipStream(handle)->totalIn;
}
static JNINativeMethod gMethods[] = {
diff --git a/luni/src/main/native/libcore_icu_AlphabeticIndex.cpp b/luni/src/main/native/libcore_icu_AlphabeticIndex.cpp
index e0638bd..acc247b 100644
--- a/luni/src/main/native/libcore_icu_AlphabeticIndex.cpp
+++ b/luni/src/main/native/libcore_icu_AlphabeticIndex.cpp
@@ -25,8 +25,8 @@
#include "unicode/alphaindex.h"
#include "unicode/uniset.h"
-static AlphabeticIndex* fromPeer(jlong peer) {
- return reinterpret_cast<AlphabeticIndex*>(static_cast<uintptr_t>(peer));
+static icu::AlphabeticIndex* fromPeer(jlong peer) {
+ return reinterpret_cast<icu::AlphabeticIndex*>(static_cast<uintptr_t>(peer));
}
static jlong AlphabeticIndex_create(JNIEnv* env, jclass, jstring javaLocaleName) {
@@ -35,7 +35,7 @@ static jlong AlphabeticIndex_create(JNIEnv* env, jclass, jstring javaLocaleName)
if (!icuLocale.valid()) {
return 0;
}
- AlphabeticIndex* ai = new AlphabeticIndex(icuLocale.locale(), status);
+ icu::AlphabeticIndex* ai = new icu::AlphabeticIndex(icuLocale.locale(), status);
if (maybeThrowIcuException(env, "AlphabeticIndex", status)) {
return 0;
}
@@ -47,19 +47,19 @@ static void AlphabeticIndex_destroy(JNIEnv*, jclass, jlong peer) {
}
static jint AlphabeticIndex_getMaxLabelCount(JNIEnv*, jclass, jlong peer) {
- AlphabeticIndex* ai = fromPeer(peer);
+ icu::AlphabeticIndex* ai = fromPeer(peer);
return ai->getMaxLabelCount();
}
static void AlphabeticIndex_setMaxLabelCount(JNIEnv* env, jclass, jlong peer, jint count) {
- AlphabeticIndex* ai = fromPeer(peer);
+ icu::AlphabeticIndex* ai = fromPeer(peer);
UErrorCode status = U_ZERO_ERROR;
ai->setMaxLabelCount(count, status);
maybeThrowIcuException(env, "AlphabeticIndex::setMaxLabelCount", status);
}
static void AlphabeticIndex_addLabels(JNIEnv* env, jclass, jlong peer, jstring javaLocaleName) {
- AlphabeticIndex* ai = fromPeer(peer);
+ icu::AlphabeticIndex* ai = fromPeer(peer);
ScopedIcuLocale icuLocale(env, javaLocaleName);
if (!icuLocale.valid()) {
return;
@@ -71,14 +71,14 @@ static void AlphabeticIndex_addLabels(JNIEnv* env, jclass, jlong peer, jstring j
static void AlphabeticIndex_addLabelRange(JNIEnv* env, jclass, jlong peer,
jint codePointStart, jint codePointEnd) {
- AlphabeticIndex* ai = fromPeer(peer);
+ icu::AlphabeticIndex* ai = fromPeer(peer);
UErrorCode status = U_ZERO_ERROR;
- ai->addLabels(UnicodeSet(codePointStart, codePointEnd), status);
+ ai->addLabels(icu::UnicodeSet(codePointStart, codePointEnd), status);
maybeThrowIcuException(env, "AlphabeticIndex::addLabels", status);
}
static jint AlphabeticIndex_getBucketCount(JNIEnv* env, jclass, jlong peer) {
- AlphabeticIndex* ai = fromPeer(peer);
+ icu::AlphabeticIndex* ai = fromPeer(peer);
UErrorCode status = U_ZERO_ERROR;
jint result = ai->getBucketCount(status);
if (maybeThrowIcuException(env, "AlphabeticIndex::getBucketCount", status)) {
@@ -88,7 +88,7 @@ static jint AlphabeticIndex_getBucketCount(JNIEnv* env, jclass, jlong peer) {
}
static jint AlphabeticIndex_getBucketIndex(JNIEnv* env, jclass, jlong peer, jstring javaString) {
- AlphabeticIndex* ai = fromPeer(peer);
+ icu::AlphabeticIndex* ai = fromPeer(peer);
ScopedJavaUnicodeString string(env, javaString);
if (!string.valid()) {
return -1;
@@ -108,7 +108,7 @@ static jstring AlphabeticIndex_getBucketLabel(JNIEnv* env, jclass, jlong peer, j
}
// Iterate to the nth bucket.
- AlphabeticIndex* ai = fromPeer(peer);
+ icu::AlphabeticIndex* ai = fromPeer(peer);
UErrorCode status = U_ZERO_ERROR;
ai->resetBucketIterator(status);
if (maybeThrowIcuException(env, "AlphabeticIndex::resetBucketIterator", status)) {
@@ -129,31 +129,31 @@ static jstring AlphabeticIndex_getBucketLabel(JNIEnv* env, jclass, jlong peer, j
return env->NewStringUTF("");
}
- const UnicodeString& label(ai->getBucketLabel());
+ const icu::UnicodeString& label(ai->getBucketLabel());
return env->NewString(label.getBuffer(), label.length());
}
static jlong AlphabeticIndex_buildImmutableIndex(JNIEnv* env, jclass, jlong peer) {
- AlphabeticIndex* ai = fromPeer(peer);
+ icu::AlphabeticIndex* ai = fromPeer(peer);
UErrorCode status = U_ZERO_ERROR;
- AlphabeticIndex::ImmutableIndex* ii = ai->buildImmutableIndex(status);
+ icu::AlphabeticIndex::ImmutableIndex* ii = ai->buildImmutableIndex(status);
if (maybeThrowIcuException(env, "AlphabeticIndex::buildImmutableIndex", status)) {
return 0;
}
return reinterpret_cast<uintptr_t>(ii);
}
-static AlphabeticIndex::ImmutableIndex* immutableIndexFromPeer(jlong peer) {
- return reinterpret_cast<AlphabeticIndex::ImmutableIndex*>(static_cast<uintptr_t>(peer));
+static icu::AlphabeticIndex::ImmutableIndex* immutableIndexFromPeer(jlong peer) {
+ return reinterpret_cast<icu::AlphabeticIndex::ImmutableIndex*>(static_cast<uintptr_t>(peer));
}
static jint ImmutableIndex_getBucketCount(JNIEnv*, jclass, jlong peer) {
- AlphabeticIndex::ImmutableIndex* ii = immutableIndexFromPeer(peer);
+ icu::AlphabeticIndex::ImmutableIndex* ii = immutableIndexFromPeer(peer);
return ii->getBucketCount();
}
static jint ImmutableIndex_getBucketIndex(JNIEnv* env, jclass, jlong peer, jstring javaString) {
- AlphabeticIndex::ImmutableIndex* ii = immutableIndexFromPeer(peer);
+ icu::AlphabeticIndex::ImmutableIndex* ii = immutableIndexFromPeer(peer);
ScopedJavaUnicodeString string(env, javaString);
if (!string.valid()) {
return -1;
@@ -167,8 +167,8 @@ static jint ImmutableIndex_getBucketIndex(JNIEnv* env, jclass, jlong peer, jstri
}
static jstring ImmutableIndex_getBucketLabel(JNIEnv* env, jclass, jlong peer, jint index) {
- AlphabeticIndex::ImmutableIndex* ii = immutableIndexFromPeer(peer);
- const AlphabeticIndex::Bucket* bucket = ii->getBucket(index);
+ icu::AlphabeticIndex::ImmutableIndex* ii = immutableIndexFromPeer(peer);
+ const icu::AlphabeticIndex::Bucket* bucket = ii->getBucket(index);
if (bucket == NULL) {
jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException", "Invalid index: %d", index);
return NULL;
@@ -179,7 +179,7 @@ static jstring ImmutableIndex_getBucketLabel(JNIEnv* env, jclass, jlong peer, ji
return env->NewStringUTF("");
}
- const UnicodeString& label(bucket->getLabel());
+ const icu::UnicodeString& label(bucket->getLabel());
return env->NewString(label.getBuffer(), label.length());
}
diff --git a/luni/src/main/native/libcore_icu_DateIntervalFormat.cpp b/luni/src/main/native/libcore_icu_DateIntervalFormat.cpp
deleted file mode 100644
index a3258c1..0000000
--- a/luni/src/main/native/libcore_icu_DateIntervalFormat.cpp
+++ /dev/null
@@ -1,79 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define LOG_TAG "DateIntervalFormat"
-
-#include "IcuUtilities.h"
-#include "JniConstants.h"
-#include "ScopedIcuLocale.h"
-#include "ScopedJavaUnicodeString.h"
-#include "UniquePtr.h"
-#include "cutils/log.h"
-#include "unicode/dtitvfmt.h"
-
-static jlong DateIntervalFormat_createDateIntervalFormat(JNIEnv* env, jclass, jstring javaSkeleton, jstring javaLocaleName, jstring javaTzName) {
- ScopedIcuLocale icuLocale(env, javaLocaleName);
- if (!icuLocale.valid()) {
- return 0;
- }
-
- ScopedJavaUnicodeString skeletonHolder(env, javaSkeleton);
- if (!skeletonHolder.valid()) {
- return 0;
- }
-
- UErrorCode status = U_ZERO_ERROR;
- DateIntervalFormat* formatter(DateIntervalFormat::createInstance(skeletonHolder.unicodeString(), icuLocale.locale(), status));
- if (maybeThrowIcuException(env, "DateIntervalFormat::createInstance", status)) {
- return 0;
- }
-
- ScopedJavaUnicodeString tzNameHolder(env, javaTzName);
- if (!tzNameHolder.valid()) {
- return 0;
- }
- formatter->adoptTimeZone(TimeZone::createTimeZone(tzNameHolder.unicodeString()));
-
- return reinterpret_cast<uintptr_t>(formatter);
-}
-
-static void DateIntervalFormat_destroyDateIntervalFormat(JNIEnv*, jclass, jlong address) {
- delete reinterpret_cast<DateIntervalFormat*>(address);
-}
-
-static jstring DateIntervalFormat_formatDateInterval(JNIEnv* env, jclass, jlong address, jlong fromDate, jlong toDate) {
- DateIntervalFormat* formatter(reinterpret_cast<DateIntervalFormat*>(address));
- DateInterval date_interval(fromDate, toDate);
-
- UnicodeString s;
- FieldPosition pos = 0;
- UErrorCode status = U_ZERO_ERROR;
- formatter->format(&date_interval, s, pos, status);
- if (maybeThrowIcuException(env, "DateIntervalFormat::format", status)) {
- return NULL;
- }
-
- return env->NewString(s.getBuffer(), s.length());
-}
-
-static JNINativeMethod gMethods[] = {
- NATIVE_METHOD(DateIntervalFormat, createDateIntervalFormat, "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)J"),
- NATIVE_METHOD(DateIntervalFormat, destroyDateIntervalFormat, "(J)V"),
- NATIVE_METHOD(DateIntervalFormat, formatDateInterval, "(JJJ)Ljava/lang/String;"),
-};
-void register_libcore_icu_DateIntervalFormat(JNIEnv* env) {
- jniRegisterNativeMethods(env, "libcore/icu/DateIntervalFormat", gMethods, NELEM(gMethods));
-}
diff --git a/luni/src/main/native/libcore_icu_ICU.cpp b/luni/src/main/native/libcore_icu_ICU.cpp
index d27b11d..d092978 100644
--- a/luni/src/main/native/libcore_icu_ICU.cpp
+++ b/luni/src/main/native/libcore_icu_ICU.cpp
@@ -25,7 +25,6 @@
#include "ScopedJavaUnicodeString.h"
#include "ScopedLocalRef.h"
#include "ScopedUtfChars.h"
-#include "UniquePtr.h"
#include "cutils/log.h"
#include "toStringArray.h"
#include "unicode/brkiter.h"
@@ -39,6 +38,7 @@
#include "unicode/locid.h"
#include "unicode/numfmt.h"
#include "unicode/strenum.h"
+#include "unicode/timezone.h"
#include "unicode/ubrk.h"
#include "unicode/ucal.h"
#include "unicode/uclean.h"
@@ -62,15 +62,9 @@
#include <sys/types.h>
#include <time.h>
#include <unistd.h>
+#include <memory>
#include <vector>
-// TODO: put this in a header file and use it everywhere!
-// DISALLOW_COPY_AND_ASSIGN disallows the copy and operator= functions.
-// It goes in the private: declarations in a class.
-#define DISALLOW_COPY_AND_ASSIGN(TypeName) \
- TypeName(const TypeName&); \
- void operator=(const TypeName&)
-
class ScopedResourceBundle {
public:
ScopedResourceBundle(UResourceBundle* bundle) : bundle_(bundle) {
@@ -121,7 +115,7 @@ static jint ICU_getCurrencyFractionDigits(JNIEnv* env, jclass, jstring javaCurre
if (!currencyCode.valid()) {
return 0;
}
- UnicodeString icuCurrencyCode(currencyCode.unicodeString());
+ icu::UnicodeString icuCurrencyCode(currencyCode.unicodeString());
UErrorCode status = U_ZERO_ERROR;
return ucurr_getDefaultFractionDigits(icuCurrencyCode.getTerminatedBuffer(), &status);
}
@@ -131,7 +125,7 @@ static jint ICU_getCurrencyNumericCode(JNIEnv* env, jclass, jstring javaCurrency
if (!currencyCode.valid()) {
return 0;
}
- UnicodeString icuCurrencyCode(currencyCode.unicodeString());
+ icu::UnicodeString icuCurrencyCode(currencyCode.unicodeString());
return ucurr_getNumericCode(icuCurrencyCode.getTerminatedBuffer());
}
@@ -187,7 +181,7 @@ static jstring getCurrencyName(JNIEnv* env, jstring javaLanguageTag, jstring jav
if (!currencyCode.valid()) {
return NULL;
}
- UnicodeString icuCurrencyCode(currencyCode.unicodeString());
+ icu::UnicodeString icuCurrencyCode(currencyCode.unicodeString());
UErrorCode status = U_ZERO_ERROR;
UBool isChoiceFormat = false;
int32_t charCount;
@@ -228,7 +222,7 @@ static jstring ICU_getDisplayCountryNative(JNIEnv* env, jclass, jstring javaTarg
return NULL;
}
- UnicodeString str;
+ icu::UnicodeString str;
icuTargetLocale.locale().getDisplayCountry(icuLocale.locale(), str);
return env->NewString(str.getBuffer(), str.length());
}
@@ -243,7 +237,7 @@ static jstring ICU_getDisplayLanguageNative(JNIEnv* env, jclass, jstring javaTar
return NULL;
}
- UnicodeString str;
+ icu::UnicodeString str;
icuTargetLocale.locale().getDisplayLanguage(icuLocale.locale(), str);
return env->NewString(str.getBuffer(), str.length());
}
@@ -258,7 +252,7 @@ static jstring ICU_getDisplayScriptNative(JNIEnv* env, jclass, jstring javaTarge
return NULL;
}
- UnicodeString str;
+ icu::UnicodeString str;
icuTargetLocale.locale().getDisplayScript(icuLocale.locale(), str);
return env->NewString(str.getBuffer(), str.length());
}
@@ -273,7 +267,7 @@ static jstring ICU_getDisplayVariantNative(JNIEnv* env, jclass, jstring javaTarg
return NULL;
}
- UnicodeString str;
+ icu::UnicodeString str;
icuTargetLocale.locale().getDisplayVariant(icuLocale.locale(), str);
return env->NewString(str.getBuffer(), str.length());
}
@@ -295,11 +289,11 @@ static jstring ICU_getISO3Language(JNIEnv* env, jclass, jstring javaLanguageTag)
}
static jobjectArray ICU_getISOCountriesNative(JNIEnv* env, jclass) {
- return toStringArray(env, Locale::getISOCountries());
+ return toStringArray(env, icu::Locale::getISOCountries());
}
static jobjectArray ICU_getISOLanguagesNative(JNIEnv* env, jclass) {
- return toStringArray(env, Locale::getISOLanguages());
+ return toStringArray(env, icu::Locale::getISOLanguages());
}
static jobjectArray ICU_getAvailableLocalesNative(JNIEnv* env, jclass) {
@@ -343,7 +337,7 @@ static void setStringArrayField(JNIEnv* env, jobject obj, const char* fieldName,
env->SetObjectField(obj, fid, value);
}
-static void setStringArrayField(JNIEnv* env, jobject obj, const char* fieldName, const UnicodeString* valueArray, int32_t size) {
+static void setStringArrayField(JNIEnv* env, jobject obj, const char* fieldName, const icu::UnicodeString* valueArray, int32_t size) {
ScopedLocalRef<jobjectArray> result(env, env->NewObjectArray(size, JniConstants::stringClass, NULL));
for (int32_t i = 0; i < size ; i++) {
ScopedLocalRef<jstring> s(env, env->NewString(valueArray[i].getBuffer(),valueArray[i].length()));
@@ -369,7 +363,7 @@ static void setStringField(JNIEnv* env, jobject obj, const char* fieldName, URes
}
}
-static void setCharField(JNIEnv* env, jobject obj, const char* fieldName, const UnicodeString& value) {
+static void setCharField(JNIEnv* env, jobject obj, const char* fieldName, const icu::UnicodeString& value) {
if (value.length() == 0) {
return;
}
@@ -377,43 +371,43 @@ static void setCharField(JNIEnv* env, jobject obj, const char* fieldName, const
env->SetCharField(obj, fid, value.charAt(0));
}
-static void setStringField(JNIEnv* env, jobject obj, const char* fieldName, const UnicodeString& value) {
+static void setStringField(JNIEnv* env, jobject obj, const char* fieldName, const icu::UnicodeString& value) {
const UChar* chars = value.getBuffer();
setStringField(env, obj, fieldName, env->NewString(chars, value.length()));
}
-static void setNumberPatterns(JNIEnv* env, jobject obj, Locale& locale) {
+static void setNumberPatterns(JNIEnv* env, jobject obj, icu::Locale& locale) {
UErrorCode status = U_ZERO_ERROR;
- UnicodeString pattern;
- UniquePtr<DecimalFormat> fmt(static_cast<DecimalFormat*>(NumberFormat::createInstance(locale, UNUM_CURRENCY, status)));
+ icu::UnicodeString pattern;
+ std::unique_ptr<icu::DecimalFormat> fmt(static_cast<icu::DecimalFormat*>(icu::NumberFormat::createInstance(locale, UNUM_CURRENCY, status)));
pattern = fmt->toPattern(pattern.remove());
setStringField(env, obj, "currencyPattern", pattern);
- fmt.reset(static_cast<DecimalFormat*>(NumberFormat::createInstance(locale, UNUM_DECIMAL, status)));
+ fmt.reset(static_cast<icu::DecimalFormat*>(icu::NumberFormat::createInstance(locale, UNUM_DECIMAL, status)));
pattern = fmt->toPattern(pattern.remove());
setStringField(env, obj, "numberPattern", pattern);
- fmt.reset(static_cast<DecimalFormat*>(NumberFormat::createInstance(locale, UNUM_PERCENT, status)));
+ fmt.reset(static_cast<icu::DecimalFormat*>(icu::NumberFormat::createInstance(locale, UNUM_PERCENT, status)));
pattern = fmt->toPattern(pattern.remove());
setStringField(env, obj, "percentPattern", pattern);
}
-static void setDecimalFormatSymbolsData(JNIEnv* env, jobject obj, Locale& locale) {
+static void setDecimalFormatSymbolsData(JNIEnv* env, jobject obj, icu::Locale& locale) {
UErrorCode status = U_ZERO_ERROR;
- DecimalFormatSymbols dfs(locale, status);
+ icu::DecimalFormatSymbols dfs(locale, status);
- setCharField(env, obj, "decimalSeparator", dfs.getSymbol(DecimalFormatSymbols::kDecimalSeparatorSymbol));
- setCharField(env, obj, "groupingSeparator", dfs.getSymbol(DecimalFormatSymbols::kGroupingSeparatorSymbol));
- setCharField(env, obj, "patternSeparator", dfs.getSymbol(DecimalFormatSymbols::kPatternSeparatorSymbol));
- setStringField(env, obj, "percent", dfs.getSymbol(DecimalFormatSymbols::kPercentSymbol));
- setCharField(env, obj, "perMill", dfs.getSymbol(DecimalFormatSymbols::kPerMillSymbol));
- setCharField(env, obj, "monetarySeparator", dfs.getSymbol(DecimalFormatSymbols::kMonetarySeparatorSymbol));
- setStringField(env, obj, "minusSign", dfs.getSymbol(DecimalFormatSymbols:: kMinusSignSymbol));
- setStringField(env, obj, "exponentSeparator", dfs.getSymbol(DecimalFormatSymbols::kExponentialSymbol));
- setStringField(env, obj, "infinity", dfs.getSymbol(DecimalFormatSymbols::kInfinitySymbol));
- setStringField(env, obj, "NaN", dfs.getSymbol(DecimalFormatSymbols::kNaNSymbol));
- setCharField(env, obj, "zeroDigit", dfs.getSymbol(DecimalFormatSymbols::kZeroDigitSymbol));
+ setCharField(env, obj, "decimalSeparator", dfs.getSymbol(icu::DecimalFormatSymbols::kDecimalSeparatorSymbol));
+ setCharField(env, obj, "groupingSeparator", dfs.getSymbol(icu::DecimalFormatSymbols::kGroupingSeparatorSymbol));
+ setCharField(env, obj, "patternSeparator", dfs.getSymbol(icu::DecimalFormatSymbols::kPatternSeparatorSymbol));
+ setStringField(env, obj, "percent", dfs.getSymbol(icu::DecimalFormatSymbols::kPercentSymbol));
+ setCharField(env, obj, "perMill", dfs.getSymbol(icu::DecimalFormatSymbols::kPerMillSymbol));
+ setCharField(env, obj, "monetarySeparator", dfs.getSymbol(icu::DecimalFormatSymbols::kMonetarySeparatorSymbol));
+ setStringField(env, obj, "minusSign", dfs.getSymbol(icu::DecimalFormatSymbols:: kMinusSignSymbol));
+ setStringField(env, obj, "exponentSeparator", dfs.getSymbol(icu::DecimalFormatSymbols::kExponentialSymbol));
+ setStringField(env, obj, "infinity", dfs.getSymbol(icu::DecimalFormatSymbols::kInfinitySymbol));
+ setStringField(env, obj, "NaN", dfs.getSymbol(icu::DecimalFormatSymbols::kNaNSymbol));
+ setCharField(env, obj, "zeroDigit", dfs.getSymbol(icu::DecimalFormatSymbols::kZeroDigitSymbol));
}
@@ -502,7 +496,7 @@ static bool getDateTimePatterns(JNIEnv* env, jobject localeData, const char* loc
return true;
}
-static bool getYesterdayTodayAndTomorrow(JNIEnv* env, jobject localeData, const Locale& locale, const char* locale_name) {
+static bool getYesterdayTodayAndTomorrow(JNIEnv* env, jobject localeData, const icu::Locale& locale, const char* locale_name) {
UErrorCode status = U_ZERO_ERROR;
ScopedResourceBundle root(ures_open(NULL, locale_name, &status));
ScopedResourceBundle fields(ures_getByKey(root.get(), "fields", NULL, &status));
@@ -512,16 +506,16 @@ static bool getYesterdayTodayAndTomorrow(JNIEnv* env, jobject localeData, const
return false;
}
- UnicodeString yesterday(ures_getUnicodeStringByKey(relative.get(), "-1", &status));
- UnicodeString today(ures_getUnicodeStringByKey(relative.get(), "0", &status));
- UnicodeString tomorrow(ures_getUnicodeStringByKey(relative.get(), "1", &status));
+ icu::UnicodeString yesterday(icu::ures_getUnicodeStringByKey(relative.get(), "-1", &status));
+ icu::UnicodeString today(icu::ures_getUnicodeStringByKey(relative.get(), "0", &status));
+ icu::UnicodeString tomorrow(icu::ures_getUnicodeStringByKey(relative.get(), "1", &status));
if (U_FAILURE(status)) {
ALOGE("Error getting yesterday/today/tomorrow for %s: %s", locale_name, u_errorName(status));
return false;
}
// We title-case the strings so they have consistent capitalization (http://b/14493853).
- UniquePtr<BreakIterator> brk(BreakIterator::createSentenceInstance(locale, status));
+ std::unique_ptr<icu::BreakIterator> brk(icu::BreakIterator::createSentenceInstance(locale, status));
if (U_FAILURE(status)) {
ALOGE("Error getting yesterday/today/tomorrow break iterator for %s: %s", locale_name, u_errorName(status));
return false;
@@ -591,7 +585,7 @@ static jboolean ICU_initLocaleDataNative(JNIEnv* env, jclass, jstring javaLangua
}
status = U_ZERO_ERROR;
- UniquePtr<Calendar> cal(Calendar::createInstance(icuLocale.locale(), status));
+ std::unique_ptr<icu::Calendar> cal(icu::Calendar::createInstance(icuLocale.locale(), status));
if (U_FAILURE(status)) {
return JNI_FALSE;
}
@@ -601,54 +595,54 @@ static jboolean ICU_initLocaleDataNative(JNIEnv* env, jclass, jstring javaLangua
// Get DateFormatSymbols.
status = U_ZERO_ERROR;
- DateFormatSymbols dateFormatSym(icuLocale.locale(), status);
+ icu::DateFormatSymbols dateFormatSym(icuLocale.locale(), status);
if (U_FAILURE(status)) {
return JNI_FALSE;
}
// Get AM/PM and BC/AD.
int32_t count = 0;
- const UnicodeString* amPmStrs = dateFormatSym.getAmPmStrings(count);
+ const icu::UnicodeString* amPmStrs = dateFormatSym.getAmPmStrings(count);
setStringArrayField(env, localeData, "amPm", amPmStrs, count);
- const UnicodeString* erasStrs = dateFormatSym.getEras(count);
+ const icu::UnicodeString* erasStrs = dateFormatSym.getEras(count);
setStringArrayField(env, localeData, "eras", erasStrs, count);
- const UnicodeString* longMonthNames =
- dateFormatSym.getMonths(count, DateFormatSymbols::FORMAT, DateFormatSymbols::WIDE);
+ const icu::UnicodeString* longMonthNames =
+ dateFormatSym.getMonths(count, icu::DateFormatSymbols::FORMAT, icu::DateFormatSymbols::WIDE);
setStringArrayField(env, localeData, "longMonthNames", longMonthNames, count);
- const UnicodeString* shortMonthNames =
- dateFormatSym.getMonths(count, DateFormatSymbols::FORMAT, DateFormatSymbols::ABBREVIATED);
+ const icu::UnicodeString* shortMonthNames =
+ dateFormatSym.getMonths(count, icu::DateFormatSymbols::FORMAT, icu::DateFormatSymbols::ABBREVIATED);
setStringArrayField(env, localeData, "shortMonthNames", shortMonthNames, count);
- const UnicodeString* tinyMonthNames =
- dateFormatSym.getMonths(count, DateFormatSymbols::FORMAT, DateFormatSymbols::NARROW);
+ const icu::UnicodeString* tinyMonthNames =
+ dateFormatSym.getMonths(count, icu::DateFormatSymbols::FORMAT, icu::DateFormatSymbols::NARROW);
setStringArrayField(env, localeData, "tinyMonthNames", tinyMonthNames, count);
- const UnicodeString* longWeekdayNames =
- dateFormatSym.getWeekdays(count, DateFormatSymbols::FORMAT, DateFormatSymbols::WIDE);
+ const icu::UnicodeString* longWeekdayNames =
+ dateFormatSym.getWeekdays(count, icu::DateFormatSymbols::FORMAT, icu::DateFormatSymbols::WIDE);
setStringArrayField(env, localeData, "longWeekdayNames", longWeekdayNames, count);
- const UnicodeString* shortWeekdayNames =
- dateFormatSym.getWeekdays(count, DateFormatSymbols::FORMAT, DateFormatSymbols::ABBREVIATED);
+ const icu::UnicodeString* shortWeekdayNames =
+ dateFormatSym.getWeekdays(count, icu::DateFormatSymbols::FORMAT, icu::DateFormatSymbols::ABBREVIATED);
setStringArrayField(env, localeData, "shortWeekdayNames", shortWeekdayNames, count);
- const UnicodeString* tinyWeekdayNames =
- dateFormatSym.getWeekdays(count, DateFormatSymbols::FORMAT, DateFormatSymbols::NARROW);
+ const icu::UnicodeString* tinyWeekdayNames =
+ dateFormatSym.getWeekdays(count, icu::DateFormatSymbols::FORMAT, icu::DateFormatSymbols::NARROW);
setStringArrayField(env, localeData, "tinyWeekdayNames", tinyWeekdayNames, count);
- const UnicodeString* longStandAloneMonthNames =
- dateFormatSym.getMonths(count, DateFormatSymbols::STANDALONE, DateFormatSymbols::WIDE);
+ const icu::UnicodeString* longStandAloneMonthNames =
+ dateFormatSym.getMonths(count, icu::DateFormatSymbols::STANDALONE, icu::DateFormatSymbols::WIDE);
setStringArrayField(env, localeData, "longStandAloneMonthNames", longStandAloneMonthNames, count);
- const UnicodeString* shortStandAloneMonthNames =
- dateFormatSym.getMonths(count, DateFormatSymbols::STANDALONE, DateFormatSymbols::ABBREVIATED);
+ const icu::UnicodeString* shortStandAloneMonthNames =
+ dateFormatSym.getMonths(count, icu::DateFormatSymbols::STANDALONE, icu::DateFormatSymbols::ABBREVIATED);
setStringArrayField(env, localeData, "shortStandAloneMonthNames", shortStandAloneMonthNames, count);
- const UnicodeString* tinyStandAloneMonthNames =
- dateFormatSym.getMonths(count, DateFormatSymbols::STANDALONE, DateFormatSymbols::NARROW);
+ const icu::UnicodeString* tinyStandAloneMonthNames =
+ dateFormatSym.getMonths(count, icu::DateFormatSymbols::STANDALONE, icu::DateFormatSymbols::NARROW);
setStringArrayField(env, localeData, "tinyStandAloneMonthNames", tinyStandAloneMonthNames, count);
- const UnicodeString* longStandAloneWeekdayNames =
- dateFormatSym.getWeekdays(count, DateFormatSymbols::STANDALONE, DateFormatSymbols::WIDE);
+ const icu::UnicodeString* longStandAloneWeekdayNames =
+ dateFormatSym.getWeekdays(count, icu::DateFormatSymbols::STANDALONE, icu::DateFormatSymbols::WIDE);
setStringArrayField(env, localeData, "longStandAloneWeekdayNames", longStandAloneWeekdayNames, count);
- const UnicodeString* shortStandAloneWeekdayNames =
- dateFormatSym.getWeekdays(count, DateFormatSymbols::STANDALONE, DateFormatSymbols::ABBREVIATED);
+ const icu::UnicodeString* shortStandAloneWeekdayNames =
+ dateFormatSym.getWeekdays(count, icu::DateFormatSymbols::STANDALONE, icu::DateFormatSymbols::ABBREVIATED);
setStringArrayField(env, localeData, "shortStandAloneWeekdayNames", shortStandAloneWeekdayNames, count);
- const UnicodeString* tinyStandAloneWeekdayNames =
- dateFormatSym.getWeekdays(count, DateFormatSymbols::STANDALONE, DateFormatSymbols::NARROW);
+ const icu::UnicodeString* tinyStandAloneWeekdayNames =
+ dateFormatSym.getWeekdays(count, icu::DateFormatSymbols::STANDALONE, icu::DateFormatSymbols::NARROW);
setStringArrayField(env, localeData, "tinyStandAloneWeekdayNames", tinyStandAloneWeekdayNames, count);
status = U_ZERO_ERROR;
@@ -687,8 +681,8 @@ static jstring ICU_toLowerCase(JNIEnv* env, jclass, jstring javaString, jstring
if (!icuLocale.valid()) {
return NULL;
}
- UnicodeString& s(scopedString.unicodeString());
- UnicodeString original(s);
+ icu::UnicodeString& s(scopedString.unicodeString());
+ icu::UnicodeString original(s);
s.toLower(icuLocale.locale());
return s == original ? javaString : env->NewString(s.getBuffer(), s.length());
}
@@ -702,8 +696,8 @@ static jstring ICU_toUpperCase(JNIEnv* env, jclass, jstring javaString, jstring
if (!icuLocale.valid()) {
return NULL;
}
- UnicodeString& s(scopedString.unicodeString());
- UnicodeString original(s);
+ icu::UnicodeString& s(scopedString.unicodeString());
+ icu::UnicodeString original(s);
s.toUpper(icuLocale.locale());
return s == original ? javaString : env->NewString(s.getBuffer(), s.length());
}
@@ -733,9 +727,18 @@ static jstring ICU_getUnicodeVersion(JNIEnv* env, jclass) {
return versionString(env, unicodeVersion);
}
+static jstring ICU_getTZDataVersion(JNIEnv* env, jclass) {
+ UErrorCode status = U_ZERO_ERROR;
+ const char* version = icu::TimeZone::getTZDataVersion(status);
+ if (maybeThrowIcuException(env, "icu::TimeZone::getTZDataVersion", status)) {
+ return NULL;
+ }
+ return env->NewStringUTF(version);
+}
+
static jobject ICU_getAvailableCurrencyCodes(JNIEnv* env, jclass) {
UErrorCode status = U_ZERO_ERROR;
- UStringEnumeration e(ucurr_openISOCurrencies(UCURR_COMMON|UCURR_NON_DEPRECATED, &status));
+ icu::UStringEnumeration e(ucurr_openISOCurrencies(UCURR_COMMON|UCURR_NON_DEPRECATED, &status));
return fromStringEnumeration(env, status, "ucurr_openISOCurrencies", &e);
}
@@ -746,7 +749,7 @@ static jstring ICU_getBestDateTimePatternNative(JNIEnv* env, jclass, jstring jav
}
UErrorCode status = U_ZERO_ERROR;
- UniquePtr<DateTimePatternGenerator> generator(DateTimePatternGenerator::createInstance(icuLocale.locale(), status));
+ std::unique_ptr<icu::DateTimePatternGenerator> generator(icu::DateTimePatternGenerator::createInstance(icuLocale.locale(), status));
if (maybeThrowIcuException(env, "DateTimePatternGenerator::createInstance", status)) {
return NULL;
}
@@ -755,7 +758,7 @@ static jstring ICU_getBestDateTimePatternNative(JNIEnv* env, jclass, jstring jav
if (!skeletonHolder.valid()) {
return NULL;
}
- UnicodeString result(generator->getBestPattern(skeletonHolder.unicodeString(), status));
+ icu::UnicodeString result(generator->getBestPattern(skeletonHolder.unicodeString(), status));
if (maybeThrowIcuException(env, "DateTimePatternGenerator::getBestPattern", status)) {
return NULL;
}
@@ -770,12 +773,12 @@ static void ICU_setDefaultLocale(JNIEnv* env, jclass, jstring javaLanguageTag) {
}
UErrorCode status = U_ZERO_ERROR;
- Locale::setDefault(icuLocale.locale(), status);
+ icu::Locale::setDefault(icuLocale.locale(), status);
maybeThrowIcuException(env, "Locale::setDefault", status);
}
static jstring ICU_getDefaultLocale(JNIEnv* env, jclass) {
- return env->NewStringUTF(Locale::getDefault().getName());
+ return env->NewStringUTF(icu::Locale::getDefault().getName());
}
static JNINativeMethod gMethods[] = {
@@ -805,28 +808,25 @@ static JNINativeMethod gMethods[] = {
NATIVE_METHOD(ICU, getISOLanguagesNative, "()[Ljava/lang/String;"),
NATIVE_METHOD(ICU, getIcuVersion, "()Ljava/lang/String;"),
NATIVE_METHOD(ICU, getScript, "(Ljava/lang/String;)Ljava/lang/String;"),
+ NATIVE_METHOD(ICU, getTZDataVersion, "()Ljava/lang/String;"),
NATIVE_METHOD(ICU, getUnicodeVersion, "()Ljava/lang/String;"),
NATIVE_METHOD(ICU, initLocaleDataNative, "(Ljava/lang/String;Llibcore/icu/LocaleData;)Z"),
NATIVE_METHOD(ICU, setDefaultLocale, "(Ljava/lang/String;)V"),
NATIVE_METHOD(ICU, toLowerCase, "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;"),
NATIVE_METHOD(ICU, toUpperCase, "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;"),
};
-void register_libcore_icu_ICU(JNIEnv* env) {
- std::string path;
- path = u_getDataDirectory();
- path += "/";
- path += U_ICUDATA_NAME;
- path += ".dat";
-
- #define FAIL_WITH_STRERROR(s) \
- ALOGE("Couldn't " s " '%s': %s", path.c_str(), strerror(errno)); \
- abort();
- #define MAYBE_FAIL_WITH_ICU_ERROR(s) \
- if (status != U_ZERO_ERROR) {\
- ALOGE("Couldn't initialize ICU (" s "): %s (%s)", u_errorName(status), path.c_str()); \
- abort(); \
- }
+#define FAIL_WITH_STRERROR(s) \
+ ALOGE("Couldn't " s " '%s': %s", path.c_str(), strerror(errno)); \
+ return FALSE;
+
+#define MAYBE_FAIL_WITH_ICU_ERROR(s) \
+ if (status != U_ZERO_ERROR) {\
+ ALOGE("Couldn't initialize ICU (" s "): %s (%s)", u_errorName(status), path.c_str()); \
+ return FALSE; \
+ }
+
+static bool mapIcuData(const std::string& path) {
// Open the file and get its length.
ScopedFd fd(open(path.c_str(), O_RDONLY));
if (fd.get() == -1) {
@@ -848,18 +848,71 @@ void register_libcore_icu_ICU(JNIEnv* env) {
FAIL_WITH_STRERROR("madvise(MADV_RANDOM)");
}
- // Tell ICU to use our memory-mapped data.
UErrorCode status = U_ZERO_ERROR;
+
+ // Tell ICU to use our memory-mapped data.
udata_setCommonData(data, &status);
MAYBE_FAIL_WITH_ICU_ERROR("udata_setCommonData");
+
+ return TRUE;
+}
+
+void register_libcore_icu_ICU(JNIEnv* env) {
+ // Check the timezone override file exists. If it does, map it first so we use it in preference
+ // to the one that shipped with the device.
+ const char* dataPathPrefix = getenv("ANDROID_DATA");
+ if (dataPathPrefix == NULL) {
+ ALOGE("ANDROID_DATA environment variable not set"); \
+ abort();
+ }
+
+ UErrorCode status = U_ZERO_ERROR;
// Tell ICU it can *only* use our memory-mapped data.
udata_setFileAccess(UDATA_NO_FILES, &status);
- MAYBE_FAIL_WITH_ICU_ERROR("udata_setFileAccess");
+ if (status != U_ZERO_ERROR) {
+ ALOGE("Couldn't initialize ICU (s_setFileAccess): %s", u_errorName(status));
+ abort();
+ }
+
+ // Map in optional TZ data files.
+ std::string dataPath;
+ dataPath = dataPathPrefix;
+ dataPath += "/misc/zoneinfo/current/icu/icu_tzdata.dat";
+
+ struct stat sb;
+ if (stat(dataPath.c_str(), &sb) == 0) {
+ ALOGD("Timezone override file found: %s", dataPath.c_str());
+ if (!mapIcuData(dataPath)) {
+ ALOGW("TZ override file %s exists but could not be loaded. Skipping.", dataPath.c_str());
+ }
+ } else {
+ ALOGD("No timezone override file found: %s", dataPath.c_str());
+ }
+
+ // Use the ICU data files that shipped with the device for everything else.
+ const char* systemPathPrefix = getenv("ANDROID_ROOT");
+ if (systemPathPrefix == NULL) {
+ ALOGE("ANDROID_ROOT environment variable not set"); \
+ abort();
+ }
+ std::string systemPath;
+ systemPath = systemPathPrefix;
+ systemPath += "/usr/icu/";
+ systemPath += U_ICUDATA_NAME;
+ systemPath += ".dat";
+
+ if (!mapIcuData(systemPath)) {
+ abort();
+ }
// Failures to find the ICU data tend to be somewhat obscure because ICU loads its data on first
// use, which can be anywhere. Force initialization up front so we can report a nice clear error
// and bail.
u_init(&status);
- MAYBE_FAIL_WITH_ICU_ERROR("u_init");
+ if (status != U_ZERO_ERROR) {\
+ ALOGE("Couldn't initialize ICU (u_init): %s", u_errorName(status));
+ abort();
+ }
+
jniRegisterNativeMethods(env, "libcore/icu/ICU", gMethods, NELEM(gMethods));
}
diff --git a/luni/src/main/native/libcore_icu_NativeBreakIterator.cpp b/luni/src/main/native/libcore_icu_NativeBreakIterator.cpp
deleted file mode 100644
index ef0c2a9..0000000
--- a/luni/src/main/native/libcore_icu_NativeBreakIterator.cpp
+++ /dev/null
@@ -1,223 +0,0 @@
-/*
- * Copyright (C) 2006 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define LOG_TAG "NativeBreakIterator"
-
-#include "IcuUtilities.h"
-#include "JNIHelp.h"
-#include "JniConstants.h"
-#include "JniException.h"
-#include "ScopedIcuLocale.h"
-#include "ScopedUtfChars.h"
-#include "unicode/brkiter.h"
-#include "unicode/putil.h"
-#include <stdlib.h>
-
-// ICU documentation: http://icu-project.org/apiref/icu4c/classBreakIterator.html
-
-static BreakIterator* toBreakIterator(jlong address) {
- return reinterpret_cast<BreakIterator*>(static_cast<uintptr_t>(address));
-}
-
-/**
- * We use ICU4C's BreakIterator class, but our input is on the Java heap and potentially moving
- * around between calls. This wrapper class ensures that our RegexMatcher is always pointing at
- * the current location of the char[]. Earlier versions of Android simply copied the data to the
- * native heap, but that's wasteful and hides allocations from the garbage collector.
- */
-class BreakIteratorAccessor {
- public:
- BreakIteratorAccessor(JNIEnv* env, jlong address, jstring javaInput, bool reset) {
- init(env, address);
- mJavaInput = javaInput;
-
- if (mJavaInput == NULL) {
- return;
- }
-
- mChars = env->GetStringChars(mJavaInput, NULL);
- if (mChars == NULL) {
- return;
- }
-
- mUText = utext_openUChars(NULL, mChars, env->GetStringLength(mJavaInput), &mStatus);
- if (mUText == NULL) {
- return;
- }
-
- if (reset) {
- mBreakIterator->setText(mUText, mStatus);
- } else {
- mBreakIterator->refreshInputText(mUText, mStatus);
- }
- }
-
- BreakIteratorAccessor(JNIEnv* env, jlong address) {
- init(env, address);
- }
-
- ~BreakIteratorAccessor() {
- utext_close(mUText);
- if (mJavaInput) {
- mEnv->ReleaseStringChars(mJavaInput, mChars);
- }
- maybeThrowIcuException(mEnv, "utext_close", mStatus);
- }
-
- BreakIterator* operator->() {
- return mBreakIterator;
- }
-
- UErrorCode& status() {
- return mStatus;
- }
-
- private:
- void init(JNIEnv* env, jlong address) {
- mEnv = env;
- mJavaInput = NULL;
- mBreakIterator = toBreakIterator(address);
- mChars = NULL;
- mStatus = U_ZERO_ERROR;
- mUText = NULL;
- }
-
- JNIEnv* mEnv;
- jstring mJavaInput;
- BreakIterator* mBreakIterator;
- const jchar* mChars;
- UErrorCode mStatus;
- UText* mUText;
-
- // Disallow copy and assignment.
- BreakIteratorAccessor(const BreakIteratorAccessor&);
- void operator=(const BreakIteratorAccessor&);
-};
-
-#define MAKE_BREAK_ITERATOR_INSTANCE(F) \
- ScopedIcuLocale icuLocale(env, javaLocaleName); \
- if (!icuLocale.valid()) { \
- return 0; \
- } \
- UErrorCode status = U_ZERO_ERROR; \
- BreakIterator* it = F(icuLocale.locale(), status); \
- if (maybeThrowIcuException(env, "ubrk_open", status)) { \
- return 0; \
- } \
- return reinterpret_cast<uintptr_t>(it)
-
-static jlong NativeBreakIterator_cloneImpl(JNIEnv* env, jclass, jlong address) {
- BreakIteratorAccessor it(env, address);
- return reinterpret_cast<uintptr_t>(it->clone());
-}
-
-static void NativeBreakIterator_closeImpl(JNIEnv*, jclass, jlong address) {
- delete toBreakIterator(address);
-}
-
-static jint NativeBreakIterator_currentImpl(JNIEnv* env, jclass, jlong address, jstring javaInput) {
- BreakIteratorAccessor it(env, address, javaInput, false);
- return it->current();
-}
-
-static jint NativeBreakIterator_firstImpl(JNIEnv* env, jclass, jlong address, jstring javaInput) {
- BreakIteratorAccessor it(env, address, javaInput, false);
- return it->first();
-}
-
-static jint NativeBreakIterator_followingImpl(JNIEnv* env, jclass, jlong address, jstring javaInput, jint offset) {
- BreakIteratorAccessor it(env, address, javaInput, false);
- return it->following(offset);
-}
-
-static jlong NativeBreakIterator_getCharacterInstanceImpl(JNIEnv* env, jclass, jstring javaLocaleName) {
- MAKE_BREAK_ITERATOR_INSTANCE(BreakIterator::createCharacterInstance);
-}
-
-static jlong NativeBreakIterator_getLineInstanceImpl(JNIEnv* env, jclass, jstring javaLocaleName) {
- MAKE_BREAK_ITERATOR_INSTANCE(BreakIterator::createLineInstance);
-}
-
-static jlong NativeBreakIterator_getSentenceInstanceImpl(JNIEnv* env, jclass, jstring javaLocaleName) {
- MAKE_BREAK_ITERATOR_INSTANCE(BreakIterator::createSentenceInstance);
-}
-
-static jlong NativeBreakIterator_getWordInstanceImpl(JNIEnv* env, jclass, jstring javaLocaleName) {
- MAKE_BREAK_ITERATOR_INSTANCE(BreakIterator::createWordInstance);
-}
-
-static jboolean NativeBreakIterator_isBoundaryImpl(JNIEnv* env, jclass, jlong address, jstring javaInput, jint offset) {
- BreakIteratorAccessor it(env, address, javaInput, false);
- return it->isBoundary(offset);
-}
-
-static jint NativeBreakIterator_lastImpl(JNIEnv* env, jclass, jlong address, jstring javaInput) {
- BreakIteratorAccessor it(env, address, javaInput, false);
- return it->last();
-}
-
-static jint NativeBreakIterator_nextImpl(JNIEnv* env, jclass, jlong address, jstring javaInput, jint n) {
- BreakIteratorAccessor it(env, address, javaInput, false);
- if (n < 0) {
- while (n++ < -1) {
- it->previous();
- }
- return it->previous();
- } else if (n == 0) {
- return it->current();
- } else {
- while (n-- > 1) {
- it->next();
- }
- return it->next();
- }
- return -1;
-}
-
-static jint NativeBreakIterator_precedingImpl(JNIEnv* env, jclass, jlong address, jstring javaInput, jint offset) {
- BreakIteratorAccessor it(env, address, javaInput, false);
- return it->preceding(offset);
-}
-
-static jint NativeBreakIterator_previousImpl(JNIEnv* env, jclass, jlong address, jstring javaInput) {
- BreakIteratorAccessor it(env, address, javaInput, false);
- return it->previous();
-}
-
-static void NativeBreakIterator_setTextImpl(JNIEnv* env, jclass, jlong address, jstring javaInput) {
- BreakIteratorAccessor it(env, address, javaInput, true);
-}
-
-static JNINativeMethod gMethods[] = {
- NATIVE_METHOD(NativeBreakIterator, cloneImpl, "(J)J"),
- NATIVE_METHOD(NativeBreakIterator, closeImpl, "(J)V"),
- NATIVE_METHOD(NativeBreakIterator, currentImpl, "(JLjava/lang/String;)I"),
- NATIVE_METHOD(NativeBreakIterator, firstImpl, "(JLjava/lang/String;)I"),
- NATIVE_METHOD(NativeBreakIterator, followingImpl, "(JLjava/lang/String;I)I"),
- NATIVE_METHOD(NativeBreakIterator, getCharacterInstanceImpl, "(Ljava/lang/String;)J"),
- NATIVE_METHOD(NativeBreakIterator, getLineInstanceImpl, "(Ljava/lang/String;)J"),
- NATIVE_METHOD(NativeBreakIterator, getSentenceInstanceImpl, "(Ljava/lang/String;)J"),
- NATIVE_METHOD(NativeBreakIterator, getWordInstanceImpl, "(Ljava/lang/String;)J"),
- NATIVE_METHOD(NativeBreakIterator, isBoundaryImpl, "(JLjava/lang/String;I)Z"),
- NATIVE_METHOD(NativeBreakIterator, lastImpl, "(JLjava/lang/String;)I"),
- NATIVE_METHOD(NativeBreakIterator, nextImpl, "(JLjava/lang/String;I)I"),
- NATIVE_METHOD(NativeBreakIterator, precedingImpl, "(JLjava/lang/String;I)I"),
- NATIVE_METHOD(NativeBreakIterator, previousImpl, "(JLjava/lang/String;)I"),
- NATIVE_METHOD(NativeBreakIterator, setTextImpl, "(JLjava/lang/String;)V"),
-};
-void register_libcore_icu_NativeBreakIterator(JNIEnv* env) {
- jniRegisterNativeMethods(env, "libcore/icu/NativeBreakIterator", gMethods, NELEM(gMethods));
-}
diff --git a/luni/src/main/native/libcore_icu_NativeCollation.cpp b/luni/src/main/native/libcore_icu_NativeCollation.cpp
index 4ce42ec..f27d72e 100644
--- a/luni/src/main/native/libcore_icu_NativeCollation.cpp
+++ b/luni/src/main/native/libcore_icu_NativeCollation.cpp
@@ -15,10 +15,10 @@
#include "JniException.h"
#include "ScopedStringChars.h"
#include "ScopedUtfChars.h"
-#include "UniquePtr.h"
#include "unicode/ucol.h"
#include "unicode/ucoleitr.h"
#include <cutils/log.h>
+#include <memory>
// Manages a UCollationElements instance along with the jchar
// array it is iterating over. The associated array can be unpinned
@@ -124,7 +124,7 @@ static jlong NativeCollation_getCollationElementIterator(JNIEnv* env, jclass, jl
return -1;
}
- UniquePtr<CollationElements> ce(new CollationElements);
+ std::unique_ptr<CollationElements> ce(new CollationElements);
UErrorCode status = ce->start(env, javaSource, toCollator(address));
maybeThrowIcuException(env, "ucol_openElements", status);
if (status == U_ZERO_ERROR) {
@@ -156,7 +156,7 @@ static jbyteArray NativeCollation_getSortKey(JNIEnv* env, jclass, jlong address,
const UCollator* collator = toCollator(address);
// The buffer size prevents reallocation for most strings.
uint8_t byteArray[128];
- UniquePtr<uint8_t[]> largerByteArray;
+ std::unique_ptr<uint8_t[]> largerByteArray;
uint8_t* usedByteArray = byteArray;
size_t byteArraySize = ucol_getSortKey(collator, source.get(), source.size(), usedByteArray, sizeof(byteArray) - 1);
if (byteArraySize > sizeof(byteArray) - 1) {
diff --git a/luni/src/main/native/libcore_icu_NativeConverter.cpp b/luni/src/main/native/libcore_icu_NativeConverter.cpp
index 8dd439a..355cc78 100644
--- a/luni/src/main/native/libcore_icu_NativeConverter.cpp
+++ b/luni/src/main/native/libcore_icu_NativeConverter.cpp
@@ -23,7 +23,6 @@
#include "ScopedPrimitiveArray.h"
#include "ScopedStringChars.h"
#include "ScopedUtfChars.h"
-#include "UniquePtr.h"
#include "cutils/log.h"
#include "toStringArray.h"
#include "unicode/ucnv.h"
@@ -32,6 +31,7 @@
#include "unicode/ustring.h"
#include "unicode/utypes.h"
+#include <memory>
#include <vector>
#include <stdlib.h>
@@ -64,7 +64,7 @@ static UConverter* toUConverter(jlong address) {
static bool collectStandardNames(JNIEnv* env, const char* canonicalName, const char* standard,
std::vector<std::string>& result) {
UErrorCode status = U_ZERO_ERROR;
- UStringEnumeration e(ucnv_openStandardNames(canonicalName, standard, &status));
+ icu::UStringEnumeration e(ucnv_openStandardNames(canonicalName, standard, &status));
if (maybeThrowIcuException(env, "ucnv_openStandardNames", status)) {
return false;
}
@@ -75,7 +75,7 @@ static bool collectStandardNames(JNIEnv* env, const char* canonicalName, const c
}
for (int32_t i = 0; i < count; ++i) {
- const UnicodeString* string = e.snext(status);
+ const icu::UnicodeString* string = e.snext(status);
if (maybeThrowIcuException(env, "StringEnumeration::snext", status)) {
return false;
}
@@ -104,7 +104,7 @@ static const char* getICUCanonicalName(const char* name) {
} else if (strstr(name, "x-") == name) {
// Check if the converter can be opened with the name given.
error = U_ZERO_ERROR;
- LocalUConverterPointer cnv(ucnv_open(name + 2, &error));
+ icu::LocalUConverterPointer cnv(ucnv_open(name + 2, &error));
if (U_SUCCESS(error)) {
return name + 2;
}
@@ -150,7 +150,7 @@ static jstring getJavaCanonicalName(JNIEnv* env, const char* icuCanonicalName) {
if (name == NULL) {
name = icuCanonicalName;
}
- UniquePtr<char[]> result(new char[2 + strlen(name) + 1]);
+ std::unique_ptr<char[]> result(new char[2 + strlen(name) + 1]);
strcpy(&result[0], "x-");
strcat(&result[0], name);
return env->NewStringUTF(&result[0]);
@@ -537,12 +537,12 @@ static jboolean NativeConverter_contains(JNIEnv* env, jclass, jstring name1, jst
}
UErrorCode errorCode = U_ZERO_ERROR;
- LocalUConverterPointer converter1(ucnv_open(name1Chars.c_str(), &errorCode));
- UnicodeSet set1;
+ icu::LocalUConverterPointer converter1(ucnv_open(name1Chars.c_str(), &errorCode));
+ icu::UnicodeSet set1;
ucnv_getUnicodeSet(&*converter1, set1.toUSet(), UCNV_ROUNDTRIP_SET, &errorCode);
- LocalUConverterPointer converter2(ucnv_open(name2Chars.c_str(), &errorCode));
- UnicodeSet set2;
+ icu::LocalUConverterPointer converter2(ucnv_open(name2Chars.c_str(), &errorCode));
+ icu::UnicodeSet set2;
ucnv_getUnicodeSet(&*converter2, set2.toUSet(), UCNV_ROUNDTRIP_SET, &errorCode);
return U_SUCCESS(errorCode) && set1.containsAll(set2);
@@ -570,7 +570,7 @@ static jobject NativeConverter_charsetForName(JNIEnv* env, jclass, jstring chars
{
// ICU doesn't offer any "isSupported", so we just open and immediately close.
UErrorCode error = U_ZERO_ERROR;
- LocalUConverterPointer cnv(ucnv_open(icuCanonicalName, &error));
+ icu::LocalUConverterPointer cnv(ucnv_open(icuCanonicalName, &error));
if (!U_SUCCESS(error)) {
return NULL;
}
diff --git a/luni/src/main/native/libcore_icu_NativeDecimalFormat.cpp b/luni/src/main/native/libcore_icu_NativeDecimalFormat.cpp
index 8e440e9..8c4a411 100644
--- a/luni/src/main/native/libcore_icu_NativeDecimalFormat.cpp
+++ b/luni/src/main/native/libcore_icu_NativeDecimalFormat.cpp
@@ -19,6 +19,7 @@
#include <stdlib.h>
#include <string.h>
+#include <memory>
#include <vector>
#include "cutils/log.h"
@@ -36,18 +37,17 @@
#include "unicode/numfmt.h"
#include "unicode/unum.h"
#include "unicode/ustring.h"
-#include "UniquePtr.h"
#include "valueOf.h"
-static DecimalFormat* toDecimalFormat(jlong addr) {
- return reinterpret_cast<DecimalFormat*>(static_cast<uintptr_t>(addr));
+static icu::DecimalFormat* toDecimalFormat(jlong addr) {
+ return reinterpret_cast<icu::DecimalFormat*>(static_cast<uintptr_t>(addr));
}
static UNumberFormat* toUNumberFormat(jlong addr) {
return reinterpret_cast<UNumberFormat*>(static_cast<uintptr_t>(addr));
}
-static DecimalFormatSymbols* makeDecimalFormatSymbols(JNIEnv* env,
+static icu::DecimalFormatSymbols* makeDecimalFormatSymbols(JNIEnv* env,
jstring currencySymbol0, jchar decimalSeparator, jchar digit, jstring exponentSeparator0,
jchar groupingSeparator0, jstring infinity0,
jstring internationalCurrencySymbol0, jstring minusSign0,
@@ -60,36 +60,41 @@ static DecimalFormatSymbols* makeDecimalFormatSymbols(JNIEnv* env,
ScopedJavaUnicodeString nan(env, nan0);
ScopedJavaUnicodeString minusSign(env, minusSign0);
ScopedJavaUnicodeString percent(env, percent0);
- UnicodeString groupingSeparator(groupingSeparator0);
-
- DecimalFormatSymbols* result = new DecimalFormatSymbols;
- result->setSymbol(DecimalFormatSymbols::kCurrencySymbol, currencySymbol.unicodeString());
- result->setSymbol(DecimalFormatSymbols::kDecimalSeparatorSymbol, UnicodeString(decimalSeparator));
- result->setSymbol(DecimalFormatSymbols::kDigitSymbol, UnicodeString(digit));
- result->setSymbol(DecimalFormatSymbols::kExponentialSymbol, exponentSeparator.unicodeString());
- result->setSymbol(DecimalFormatSymbols::kGroupingSeparatorSymbol, groupingSeparator);
- result->setSymbol(DecimalFormatSymbols::kMonetaryGroupingSeparatorSymbol, groupingSeparator);
- result->setSymbol(DecimalFormatSymbols::kInfinitySymbol, infinity.unicodeString());
- result->setSymbol(DecimalFormatSymbols::kIntlCurrencySymbol, internationalCurrencySymbol.unicodeString());
- result->setSymbol(DecimalFormatSymbols::kMinusSignSymbol, minusSign.unicodeString());
- result->setSymbol(DecimalFormatSymbols::kMonetarySeparatorSymbol, UnicodeString(monetaryDecimalSeparator));
- result->setSymbol(DecimalFormatSymbols::kNaNSymbol, nan.unicodeString());
- result->setSymbol(DecimalFormatSymbols::kPatternSeparatorSymbol, UnicodeString(patternSeparator));
- result->setSymbol(DecimalFormatSymbols::kPercentSymbol, percent.unicodeString());
- result->setSymbol(DecimalFormatSymbols::kPerMillSymbol, UnicodeString(perMill));
+ icu::UnicodeString groupingSeparator(groupingSeparator0);
+
+ UErrorCode status = U_ZERO_ERROR;
+ std::unique_ptr<icu::DecimalFormatSymbols> result(icu::DecimalFormatSymbols::createWithLastResortData(status));
+ if (maybeThrowIcuException(env, "DecimalFormatSymbols::createWithLastResortData", status)) {
+ return NULL;
+ }
+
+ result->setSymbol(icu::DecimalFormatSymbols::kCurrencySymbol, currencySymbol.unicodeString());
+ result->setSymbol(icu::DecimalFormatSymbols::kDecimalSeparatorSymbol, icu::UnicodeString(decimalSeparator));
+ result->setSymbol(icu::DecimalFormatSymbols::kDigitSymbol, icu::UnicodeString(digit));
+ result->setSymbol(icu::DecimalFormatSymbols::kExponentialSymbol, exponentSeparator.unicodeString());
+ result->setSymbol(icu::DecimalFormatSymbols::kGroupingSeparatorSymbol, groupingSeparator);
+ result->setSymbol(icu::DecimalFormatSymbols::kMonetaryGroupingSeparatorSymbol, groupingSeparator);
+ result->setSymbol(icu::DecimalFormatSymbols::kInfinitySymbol, infinity.unicodeString());
+ result->setSymbol(icu::DecimalFormatSymbols::kIntlCurrencySymbol, internationalCurrencySymbol.unicodeString());
+ result->setSymbol(icu::DecimalFormatSymbols::kMinusSignSymbol, minusSign.unicodeString());
+ result->setSymbol(icu::DecimalFormatSymbols::kMonetarySeparatorSymbol, icu::UnicodeString(monetaryDecimalSeparator));
+ result->setSymbol(icu::DecimalFormatSymbols::kNaNSymbol, nan.unicodeString());
+ result->setSymbol(icu::DecimalFormatSymbols::kPatternSeparatorSymbol, icu::UnicodeString(patternSeparator));
+ result->setSymbol(icu::DecimalFormatSymbols::kPercentSymbol, percent.unicodeString());
+ result->setSymbol(icu::DecimalFormatSymbols::kPerMillSymbol, icu::UnicodeString(perMill));
// java.text.DecimalFormatSymbols just uses a zero digit,
// but ICU >= 4.6 has a field for each decimal digit.
- result->setSymbol(DecimalFormatSymbols::kZeroDigitSymbol, UnicodeString(zeroDigit + 0));
- result->setSymbol(DecimalFormatSymbols::kOneDigitSymbol, UnicodeString(zeroDigit + 1));
- result->setSymbol(DecimalFormatSymbols::kTwoDigitSymbol, UnicodeString(zeroDigit + 2));
- result->setSymbol(DecimalFormatSymbols::kThreeDigitSymbol, UnicodeString(zeroDigit + 3));
- result->setSymbol(DecimalFormatSymbols::kFourDigitSymbol, UnicodeString(zeroDigit + 4));
- result->setSymbol(DecimalFormatSymbols::kFiveDigitSymbol, UnicodeString(zeroDigit + 5));
- result->setSymbol(DecimalFormatSymbols::kSixDigitSymbol, UnicodeString(zeroDigit + 6));
- result->setSymbol(DecimalFormatSymbols::kSevenDigitSymbol, UnicodeString(zeroDigit + 7));
- result->setSymbol(DecimalFormatSymbols::kEightDigitSymbol, UnicodeString(zeroDigit + 8));
- result->setSymbol(DecimalFormatSymbols::kNineDigitSymbol, UnicodeString(zeroDigit + 9));
- return result;
+ result->setSymbol(icu::DecimalFormatSymbols::kZeroDigitSymbol, icu::UnicodeString(zeroDigit + 0));
+ result->setSymbol(icu::DecimalFormatSymbols::kOneDigitSymbol, icu::UnicodeString(zeroDigit + 1));
+ result->setSymbol(icu::DecimalFormatSymbols::kTwoDigitSymbol, icu::UnicodeString(zeroDigit + 2));
+ result->setSymbol(icu::DecimalFormatSymbols::kThreeDigitSymbol, icu::UnicodeString(zeroDigit + 3));
+ result->setSymbol(icu::DecimalFormatSymbols::kFourDigitSymbol, icu::UnicodeString(zeroDigit + 4));
+ result->setSymbol(icu::DecimalFormatSymbols::kFiveDigitSymbol, icu::UnicodeString(zeroDigit + 5));
+ result->setSymbol(icu::DecimalFormatSymbols::kSixDigitSymbol, icu::UnicodeString(zeroDigit + 6));
+ result->setSymbol(icu::DecimalFormatSymbols::kSevenDigitSymbol, icu::UnicodeString(zeroDigit + 7));
+ result->setSymbol(icu::DecimalFormatSymbols::kEightDigitSymbol, icu::UnicodeString(zeroDigit + 8));
+ result->setSymbol(icu::DecimalFormatSymbols::kNineDigitSymbol, icu::UnicodeString(zeroDigit + 9));
+ return result.release();
}
static void NativeDecimalFormat_setDecimalFormatSymbols(JNIEnv* env, jclass, jlong addr,
@@ -98,7 +103,7 @@ static void NativeDecimalFormat_setDecimalFormatSymbols(JNIEnv* env, jclass, jlo
jstring internationalCurrencySymbol, jstring minusSign,
jchar monetaryDecimalSeparator, jstring nan, jchar patternSeparator,
jstring percent, jchar perMill, jchar zeroDigit) {
- DecimalFormatSymbols* symbols = makeDecimalFormatSymbols(env,
+ icu::DecimalFormatSymbols* symbols = makeDecimalFormatSymbols(env,
currencySymbol, decimalSeparator, digit, exponentSeparator, groupingSeparator,
infinity, internationalCurrencySymbol, minusSign,
monetaryDecimalSeparator, nan, patternSeparator, percent, perMill,
@@ -118,12 +123,12 @@ static jlong NativeDecimalFormat_open(JNIEnv* env, jclass, jstring pattern0,
if (!pattern.valid()) {
return 0;
}
- DecimalFormatSymbols* symbols = makeDecimalFormatSymbols(env,
+ icu::DecimalFormatSymbols* symbols = makeDecimalFormatSymbols(env,
currencySymbol, decimalSeparator, digit, exponentSeparator, groupingSeparator,
infinity, internationalCurrencySymbol, minusSign,
monetaryDecimalSeparator, nan, patternSeparator, percent, perMill,
zeroDigit);
- DecimalFormat* fmt = new DecimalFormat(pattern.unicodeString(), symbols, parseError, status);
+ icu::DecimalFormat* fmt = new icu::DecimalFormat(pattern.unicodeString(), symbols, parseError, status);
if (fmt == NULL) {
delete symbols;
}
@@ -136,8 +141,8 @@ static void NativeDecimalFormat_close(JNIEnv*, jclass, jlong addr) {
}
static void NativeDecimalFormat_setRoundingMode(JNIEnv*, jclass, jlong addr, jint mode, jdouble increment) {
- DecimalFormat* fmt = toDecimalFormat(addr);
- fmt->setRoundingMode(static_cast<DecimalFormat::ERoundingMode>(mode));
+ icu::DecimalFormat* fmt = toDecimalFormat(addr);
+ fmt->setRoundingMode(static_cast<icu::DecimalFormat::ERoundingMode>(mode));
fmt->setRoundingIncrement(increment);
}
@@ -179,7 +184,7 @@ static jstring NativeDecimalFormat_getTextAttribute(JNIEnv* env, jclass, jlong a
UNumberFormatTextAttribute attr = static_cast<UNumberFormatTextAttribute>(javaAttr);
// Find out how long the result will be...
- UniquePtr<UChar[]> chars;
+ std::unique_ptr<UChar[]> chars;
uint32_t charCount = 0;
uint32_t desiredCount = unum_getTextAttribute(fmt, attr, chars.get(), charCount, &status);
if (status == U_BUFFER_OVERFLOW_ERROR) {
@@ -197,7 +202,7 @@ static void NativeDecimalFormat_applyPatternImpl(JNIEnv* env, jclass, jlong addr
if (!pattern.valid()) {
return;
}
- DecimalFormat* fmt = toDecimalFormat(addr);
+ icu::DecimalFormat* fmt = toDecimalFormat(addr);
UErrorCode status = U_ZERO_ERROR;
const char* function;
if (localized) {
@@ -211,8 +216,8 @@ static void NativeDecimalFormat_applyPatternImpl(JNIEnv* env, jclass, jlong addr
}
static jstring NativeDecimalFormat_toPatternImpl(JNIEnv* env, jclass, jlong addr, jboolean localized) {
- DecimalFormat* fmt = toDecimalFormat(addr);
- UnicodeString pattern;
+ icu::DecimalFormat* fmt = toDecimalFormat(addr);
+ icu::UnicodeString pattern;
if (localized) {
fmt->toLocalizedPattern(pattern);
} else {
@@ -221,12 +226,12 @@ static jstring NativeDecimalFormat_toPatternImpl(JNIEnv* env, jclass, jlong addr
return env->NewString(pattern.getBuffer(), pattern.length());
}
-static jcharArray formatResult(JNIEnv* env, const UnicodeString& s, FieldPositionIterator* fpi, jobject javaFieldPositionIterator) {
+static jcharArray formatResult(JNIEnv* env, const icu::UnicodeString& s, icu::FieldPositionIterator* fpi, jobject javaFieldPositionIterator) {
static jmethodID gFPI_setData = env->GetMethodID(JniConstants::fieldPositionIteratorClass, "setData", "([I)V");
if (fpi != NULL) {
std::vector<int32_t> data;
- FieldPosition fp;
+ icu::FieldPosition fp;
while (fpi->next(fp)) {
data.push_back(fp.getField());
data.push_back(fp.getBeginIndex());
@@ -258,10 +263,10 @@ static jcharArray formatResult(JNIEnv* env, const UnicodeString& s, FieldPositio
template <typename T>
static jcharArray format(JNIEnv* env, jlong addr, jobject javaFieldPositionIterator, T value) {
UErrorCode status = U_ZERO_ERROR;
- UnicodeString s;
- DecimalFormat* fmt = toDecimalFormat(addr);
- FieldPositionIterator nativeFieldPositionIterator;
- FieldPositionIterator* fpi = javaFieldPositionIterator ? &nativeFieldPositionIterator : NULL;
+ icu::UnicodeString s;
+ icu::DecimalFormat* fmt = toDecimalFormat(addr);
+ icu::FieldPositionIterator nativeFieldPositionIterator;
+ icu::FieldPositionIterator* fpi = javaFieldPositionIterator ? &nativeFieldPositionIterator : NULL;
fmt->format(value, s, fpi, status);
if (maybeThrowIcuException(env, "DecimalFormat::format", status)) {
return NULL;
@@ -282,7 +287,7 @@ static jcharArray NativeDecimalFormat_formatDigitList(JNIEnv* env, jclass, jlong
if (chars.c_str() == NULL) {
return NULL;
}
- StringPiece sp(chars.c_str());
+ icu::StringPiece sp(chars.c_str());
return format(env, addr, javaFieldPositionIterator, sp);
}
@@ -293,7 +298,7 @@ static jobject newBigDecimal(JNIEnv* env, const char* value, jsize len) {
// value is a UTF-8 string of invariant characters, but isn't guaranteed to be
// null-terminated. NewStringUTF requires a terminated UTF-8 string. So we copy the
// data to jchars using UnicodeString, and call NewString instead.
- UnicodeString tmp(value, len, UnicodeString::kInvariant);
+ icu::UnicodeString tmp(value, len, icu::UnicodeString::kInvariant);
jobject str = env->NewString(tmp.getBuffer(), tmp.length());
return env->NewObject(JniConstants::bigDecimalClass, gBigDecimal_init, str);
}
@@ -318,9 +323,9 @@ static jobject NativeDecimalFormat_parse(JNIEnv* env, jclass, jlong addr, jstrin
return NULL;
}
- Formattable res;
- ParsePosition pp(parsePos);
- DecimalFormat* fmt = toDecimalFormat(addr);
+ icu::Formattable res;
+ icu::ParsePosition pp(parsePos);
+ icu::DecimalFormat* fmt = toDecimalFormat(addr);
fmt->parse(src.unicodeString(), res, pp);
if (pp.getErrorIndex() == -1) {
@@ -332,7 +337,7 @@ static jobject NativeDecimalFormat_parse(JNIEnv* env, jclass, jlong addr, jstrin
if (parseBigDecimal) {
UErrorCode status = U_ZERO_ERROR;
- StringPiece str = res.getDecimalNumber(status);
+ icu::StringPiece str = res.getDecimalNumber(status);
if (U_SUCCESS(status)) {
int len = str.length();
const char* data = str.data();
@@ -348,15 +353,15 @@ static jobject NativeDecimalFormat_parse(JNIEnv* env, jclass, jlong addr, jstrin
}
switch (res.getType()) {
- case Formattable::kDouble: return doubleValueOf(env, res.getDouble());
- case Formattable::kLong: return longValueOf(env, res.getLong());
- case Formattable::kInt64: return longValueOf(env, res.getInt64());
+ case icu::Formattable::kDouble: return doubleValueOf(env, res.getDouble());
+ case icu::Formattable::kLong: return longValueOf(env, res.getLong());
+ case icu::Formattable::kInt64: return longValueOf(env, res.getInt64());
default: return NULL;
}
}
static jlong NativeDecimalFormat_cloneImpl(JNIEnv*, jclass, jlong addr) {
- DecimalFormat* fmt = toDecimalFormat(addr);
+ icu::DecimalFormat* fmt = toDecimalFormat(addr);
return reinterpret_cast<uintptr_t>(fmt->clone());
}
diff --git a/luni/src/main/native/libcore_icu_NativeIDN.cpp b/luni/src/main/native/libcore_icu_NativeIDN.cpp
index 16a6e1c..43f3ce5 100644
--- a/luni/src/main/native/libcore_icu_NativeIDN.cpp
+++ b/luni/src/main/native/libcore_icu_NativeIDN.cpp
@@ -39,9 +39,18 @@ static jstring NativeIDN_convertImpl(JNIEnv* env, jclass, jstring javaSrc, jint
}
UChar dst[256];
UErrorCode status = U_ZERO_ERROR;
+
+ // We're stuck implementing IDNA-2003 for now since that's what we specify.
+ //
+ // TODO: Change our spec to IDNA-2008 + UTS-46 compatibility processing if
+ // it's safe enough.
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
size_t resultLength = toAscii
? uidna_IDNToASCII(src.get(), src.size(), &dst[0], sizeof(dst), flags, NULL, &status)
: uidna_IDNToUnicode(src.get(), src.size(), &dst[0], sizeof(dst), flags, NULL, &status);
+#pragma GCC diagnostic pop
+
if (U_FAILURE(status)) {
jniThrowException(env, "java/lang/IllegalArgumentException", u_errorName(status));
return NULL;
diff --git a/luni/src/main/native/libcore_icu_NativeNormalizer.cpp b/luni/src/main/native/libcore_icu_NativeNormalizer.cpp
index 8ae42d9..2d5e282 100644
--- a/luni/src/main/native/libcore_icu_NativeNormalizer.cpp
+++ b/luni/src/main/native/libcore_icu_NativeNormalizer.cpp
@@ -30,8 +30,8 @@ static jstring NativeNormalizer_normalizeImpl(JNIEnv* env, jclass, jstring s, ji
}
UNormalizationMode mode = static_cast<UNormalizationMode>(intMode);
UErrorCode status = U_ZERO_ERROR;
- UnicodeString dst;
- Normalizer::normalize(src.unicodeString(), mode, 0, dst, status);
+ icu::UnicodeString dst;
+ icu::Normalizer::normalize(src.unicodeString(), mode, 0, dst, status);
maybeThrowIcuException(env, "Normalizer::normalize", status);
return dst.isBogus() ? NULL : env->NewString(dst.getBuffer(), dst.length());
}
@@ -43,7 +43,7 @@ static jboolean NativeNormalizer_isNormalizedImpl(JNIEnv* env, jclass, jstring s
}
UNormalizationMode mode = static_cast<UNormalizationMode>(intMode);
UErrorCode status = U_ZERO_ERROR;
- UBool result = Normalizer::isNormalized(src.unicodeString(), mode, status);
+ UBool result = icu::Normalizer::isNormalized(src.unicodeString(), mode, status);
maybeThrowIcuException(env, "Normalizer::isNormalized", status);
return result;
}
diff --git a/luni/src/main/native/libcore_icu_NativePluralRules.cpp b/luni/src/main/native/libcore_icu_NativePluralRules.cpp
index 8910a8c..f278485 100644
--- a/luni/src/main/native/libcore_icu_NativePluralRules.cpp
+++ b/luni/src/main/native/libcore_icu_NativePluralRules.cpp
@@ -25,8 +25,8 @@
#include <string>
-static PluralRules* toPluralRules(jlong address) {
- return reinterpret_cast<PluralRules*>(static_cast<uintptr_t>(address));
+static icu::PluralRules* toPluralRules(jlong address) {
+ return reinterpret_cast<icu::PluralRules*>(static_cast<uintptr_t>(address));
}
static void NativePluralRules_finalizeImpl(JNIEnv*, jclass, jlong address) {
@@ -48,15 +48,15 @@ static jlong NativePluralRules_forLocaleImpl(JNIEnv* env, jclass, jstring javaLo
localeName[1] = 'i';
}
- Locale locale = Locale::createFromName(localeName.c_str());
+ icu::Locale locale = icu::Locale::createFromName(localeName.c_str());
UErrorCode status = U_ZERO_ERROR;
- PluralRules* result = PluralRules::forLocale(locale, status);
+ icu::PluralRules* result = icu::PluralRules::forLocale(locale, status);
maybeThrowIcuException(env, "PluralRules::forLocale", status);
return reinterpret_cast<uintptr_t>(result);
}
static jint NativePluralRules_quantityForIntImpl(JNIEnv*, jclass, jlong address, jint value) {
- UnicodeString keyword = toPluralRules(address)->select(value);
+ icu::UnicodeString keyword = toPluralRules(address)->select(value);
if (keyword == "zero") {
return 0;
} else if (keyword == "one") {
diff --git a/luni/src/main/native/libcore_icu_TimeZoneNames.cpp b/luni/src/main/native/libcore_icu_TimeZoneNames.cpp
index a7c9098..d30e7a3 100644
--- a/luni/src/main/native/libcore_icu_TimeZoneNames.cpp
+++ b/luni/src/main/native/libcore_icu_TimeZoneNames.cpp
@@ -16,6 +16,8 @@
#define LOG_TAG "TimeZoneNames"
+#include <memory>
+
#include "IcuUtilities.h"
#include "JNIHelp.h"
#include "JniConstants.h"
@@ -24,32 +26,31 @@
#include "ScopedJavaUnicodeString.h"
#include "ScopedLocalRef.h"
#include "ScopedUtfChars.h"
-#include "UniquePtr.h"
#include "unicode/calendar.h"
#include "unicode/timezone.h"
#include "unicode/tznames.h"
-static bool isUtc(const UnicodeString& id) {
- static const UnicodeString kEtcUct("Etc/UCT", 7, US_INV);
- static const UnicodeString kEtcUtc("Etc/UTC", 7, US_INV);
- static const UnicodeString kEtcUniversal("Etc/Universal", 13, US_INV);
- static const UnicodeString kEtcZulu("Etc/Zulu", 8, US_INV);
+static bool isUtc(const icu::UnicodeString& id) {
+ static const icu::UnicodeString kEtcUct("Etc/UCT", 7, US_INV);
+ static const icu::UnicodeString kEtcUtc("Etc/UTC", 7, US_INV);
+ static const icu::UnicodeString kEtcUniversal("Etc/Universal", 13, US_INV);
+ static const icu::UnicodeString kEtcZulu("Etc/Zulu", 8, US_INV);
- static const UnicodeString kUct("UCT", 3, US_INV);
- static const UnicodeString kUtc("UTC", 3, US_INV);
- static const UnicodeString kUniversal("Universal", 9, US_INV);
- static const UnicodeString kZulu("Zulu", 4, US_INV);
+ static const icu::UnicodeString kUct("UCT", 3, US_INV);
+ static const icu::UnicodeString kUtc("UTC", 3, US_INV);
+ static const icu::UnicodeString kUniversal("Universal", 9, US_INV);
+ static const icu::UnicodeString kZulu("Zulu", 4, US_INV);
return id == kEtcUct || id == kEtcUtc || id == kEtcUniversal || id == kEtcZulu ||
id == kUct || id == kUtc || id == kUniversal || id == kZulu;
}
-static bool setStringArrayElement(JNIEnv* env, jobjectArray array, int i, const UnicodeString& s) {
+static bool setStringArrayElement(JNIEnv* env, jobjectArray array, int i, const icu::UnicodeString& s) {
// Fill in whatever we got. We don't use the display names if they're "GMT[+-]xx:xx"
// because icu4c doesn't use the up-to-date time zone transition data, so it gets these
// wrong. TimeZone.getDisplayName creates accurate names on demand.
// TODO: investigate whether it's worth doing that work once in the Java wrapper instead of on-demand.
- static const UnicodeString kGmt("GMT", 3, US_INV);
+ static const icu::UnicodeString kGmt("GMT", 3, US_INV);
if (!s.isBogus() && !s.startsWith(kGmt)) {
ScopedLocalRef<jstring> javaString(env, env->NewString(s.getBuffer(), s.length()));
if (javaString.get() == NULL) {
@@ -67,14 +68,14 @@ static void TimeZoneNames_fillZoneStrings(JNIEnv* env, jclass, jstring javaLocal
}
UErrorCode status = U_ZERO_ERROR;
- UniquePtr<TimeZoneNames> names(TimeZoneNames::createInstance(icuLocale.locale(), status));
+ std::unique_ptr<icu::TimeZoneNames> names(icu::TimeZoneNames::createInstance(icuLocale.locale(), status));
if (maybeThrowIcuException(env, "TimeZoneNames::createInstance", status)) {
return;
}
- const UDate now(Calendar::getNow());
+ const UDate now(icu::Calendar::getNow());
- static const UnicodeString kUtc("UTC", 3, US_INV);
+ static const icu::UnicodeString kUtc("UTC", 3, US_INV);
size_t id_count = env->GetArrayLength(result);
for (size_t i = 0; i < id_count; ++i) {
@@ -87,13 +88,13 @@ static void TimeZoneNames_fillZoneStrings(JNIEnv* env, jclass, jstring javaLocal
return;
}
- UnicodeString long_std;
+ icu::UnicodeString long_std;
names->getDisplayName(zone_id.unicodeString(), UTZNM_LONG_STANDARD, now, long_std);
- UnicodeString short_std;
+ icu::UnicodeString short_std;
names->getDisplayName(zone_id.unicodeString(), UTZNM_SHORT_STANDARD, now, short_std);
- UnicodeString long_dst;
+ icu::UnicodeString long_dst;
names->getDisplayName(zone_id.unicodeString(), UTZNM_LONG_DAYLIGHT, now, long_dst);
- UnicodeString short_dst;
+ icu::UnicodeString short_dst;
names->getDisplayName(zone_id.unicodeString(), UTZNM_SHORT_DAYLIGHT, now, short_dst);
if (isUtc(zone_id.unicodeString())) {
@@ -123,7 +124,7 @@ static jstring TimeZoneNames_getExemplarLocation(JNIEnv* env, jclass, jstring ja
}
UErrorCode status = U_ZERO_ERROR;
- UniquePtr<TimeZoneNames> names(TimeZoneNames::createInstance(icuLocale.locale(), status));
+ std::unique_ptr<icu::TimeZoneNames> names(icu::TimeZoneNames::createInstance(icuLocale.locale(), status));
if (maybeThrowIcuException(env, "TimeZoneNames::createInstance", status)) {
return NULL;
}
@@ -133,8 +134,8 @@ static jstring TimeZoneNames_getExemplarLocation(JNIEnv* env, jclass, jstring ja
return NULL;
}
- UnicodeString s;
- const UDate now(Calendar::getNow());
+ icu::UnicodeString s;
+ const UDate now(icu::Calendar::getNow());
names->getDisplayName(tz.unicodeString(), UTZNM_EXEMPLAR_LOCATION, now, s);
return env->NewString(s.getBuffer(), s.length());
}
diff --git a/luni/src/main/native/libcore_icu_Transliterator.cpp b/luni/src/main/native/libcore_icu_Transliterator.cpp
index 0c52053..ae21565 100644
--- a/luni/src/main/native/libcore_icu_Transliterator.cpp
+++ b/luni/src/main/native/libcore_icu_Transliterator.cpp
@@ -23,8 +23,8 @@
#include "ScopedJavaUnicodeString.h"
#include "unicode/translit.h"
-static Transliterator* fromPeer(jlong peer) {
- return reinterpret_cast<Transliterator*>(static_cast<uintptr_t>(peer));
+static icu::Transliterator* fromPeer(jlong peer) {
+ return reinterpret_cast<icu::Transliterator*>(static_cast<uintptr_t>(peer));
}
static jlong Transliterator_create(JNIEnv* env, jclass, jstring javaId) {
@@ -33,7 +33,7 @@ static jlong Transliterator_create(JNIEnv* env, jclass, jstring javaId) {
return 0;
}
UErrorCode status = U_ZERO_ERROR;
- Transliterator* t = Transliterator::createInstance(id.unicodeString(), UTRANS_FORWARD, status);
+ icu::Transliterator* t = icu::Transliterator::createInstance(id.unicodeString(), UTRANS_FORWARD, status);
if (maybeThrowIcuException(env, "Transliterator::createInstance", status)) {
return 0;
}
@@ -46,18 +46,18 @@ static void Transliterator_destroy(JNIEnv*, jclass, jlong peer) {
static jobjectArray Transliterator_getAvailableIDs(JNIEnv* env, jclass) {
UErrorCode status = U_ZERO_ERROR;
- StringEnumeration* e = Transliterator::getAvailableIDs(status);
+ icu::StringEnumeration* e = icu::Transliterator::getAvailableIDs(status);
return fromStringEnumeration(env, status, "Transliterator::getAvailableIDs", e);
}
static jstring Transliterator_transliterate(JNIEnv* env, jclass, jlong peer, jstring javaString) {
- Transliterator* t = fromPeer(peer);
+ icu::Transliterator* t = fromPeer(peer);
ScopedJavaUnicodeString string(env, javaString);
if (!string.valid()) {
return NULL;
}
- UnicodeString& s(string.unicodeString());
+ icu::UnicodeString& s(string.unicodeString());
t->transliterate(s);
return env->NewString(s.getBuffer(), s.length());
}
diff --git a/luni/src/main/native/libcore_io_Memory.cpp b/luni/src/main/native/libcore_io_Memory.cpp
index 9edbfb8..5122a6c 100644
--- a/luni/src/main/native/libcore_io_Memory.cpp
+++ b/luni/src/main/native/libcore_io_Memory.cpp
@@ -21,32 +21,12 @@
#include "Portability.h"
#include "ScopedBytes.h"
#include "ScopedPrimitiveArray.h"
-#include "UniquePtr.h"
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>
-#if defined(__arm__)
-// 32-bit ARM has load/store alignment restrictions for longs.
-#define LONG_ALIGNMENT_MASK 0x3
-#define INT_ALIGNMENT_MASK 0x0
-#define SHORT_ALIGNMENT_MASK 0x0
-#elif defined(__mips__)
-// MIPS has load/store alignment restrictions for longs, ints and shorts.
-#define LONG_ALIGNMENT_MASK 0x7
-#define INT_ALIGNMENT_MASK 0x3
-#define SHORT_ALIGNMENT_MASK 0x1
-#elif defined(__aarch64__) || defined(__i386__) || defined(__x86_64__)
-// These architectures can load anything at any alignment.
-#define LONG_ALIGNMENT_MASK 0x0
-#define INT_ALIGNMENT_MASK 0x0
-#define SHORT_ALIGNMENT_MASK 0x0
-#else
-#error unknown load/store alignment restrictions for this architecture
-#endif
-
// Use packed structures for access to unaligned data on targets with alignment restrictions.
// The compiler will generate appropriate code to access these structures without
// generating alignment exceptions.
@@ -82,63 +62,31 @@ static inline void swapShorts(jshort* dstShorts, const jshort* srcShorts, size_t
// Do 32-bit swaps as long as possible...
jint* dst = reinterpret_cast<jint*>(dstShorts);
const jint* src = reinterpret_cast<const jint*>(srcShorts);
-
- if ((reinterpret_cast<uintptr_t>(dst) & INT_ALIGNMENT_MASK) == 0 &&
- (reinterpret_cast<uintptr_t>(src) & INT_ALIGNMENT_MASK) == 0) {
- for (size_t i = 0; i < count / 2; ++i) {
- jint v = *src++;
- *dst++ = bswap_2x16(v);
- }
- // ...with one last 16-bit swap if necessary.
- if ((count % 2) != 0) {
- jshort v = *reinterpret_cast<const jshort*>(src);
- *reinterpret_cast<jshort*>(dst) = bswap_16(v);
- }
- } else {
- for (size_t i = 0; i < count / 2; ++i) {
- jint v = get_unaligned<jint>(src++);
- put_unaligned<jint>(dst++, bswap_2x16(v));
- }
- if ((count % 2) != 0) {
- jshort v = get_unaligned<jshort>(reinterpret_cast<const jshort*>(src));
- put_unaligned<jshort>(reinterpret_cast<jshort*>(dst), bswap_16(v));
- }
+ for (size_t i = 0; i < count / 2; ++i) {
+ jint v = get_unaligned<jint>(src++);
+ put_unaligned<jint>(dst++, bswap_2x16(v));
+ }
+ if ((count % 2) != 0) {
+ jshort v = get_unaligned<jshort>(reinterpret_cast<const jshort*>(src));
+ put_unaligned<jshort>(reinterpret_cast<jshort*>(dst), bswap_16(v));
}
}
static inline void swapInts(jint* dstInts, const jint* srcInts, size_t count) {
- if ((reinterpret_cast<uintptr_t>(dstInts) & INT_ALIGNMENT_MASK) == 0 &&
- (reinterpret_cast<uintptr_t>(srcInts) & INT_ALIGNMENT_MASK) == 0) {
- for (size_t i = 0; i < count; ++i) {
- jint v = *srcInts++;
- *dstInts++ = bswap_32(v);
- }
- } else {
- for (size_t i = 0; i < count; ++i) {
- jint v = get_unaligned<int>(srcInts++);
- put_unaligned<jint>(dstInts++, bswap_32(v));
- }
+ for (size_t i = 0; i < count; ++i) {
+ jint v = get_unaligned<int>(srcInts++);
+ put_unaligned<jint>(dstInts++, bswap_32(v));
}
}
static inline void swapLongs(jlong* dstLongs, const jlong* srcLongs, size_t count) {
jint* dst = reinterpret_cast<jint*>(dstLongs);
const jint* src = reinterpret_cast<const jint*>(srcLongs);
- if ((reinterpret_cast<uintptr_t>(dstLongs) & INT_ALIGNMENT_MASK) == 0 &&
- (reinterpret_cast<uintptr_t>(srcLongs) & INT_ALIGNMENT_MASK) == 0) {
- for (size_t i = 0; i < count; ++i) {
- jint v1 = *src++;
- jint v2 = *src++;
- *dst++ = bswap_32(v2);
- *dst++ = bswap_32(v1);
- }
- } else {
- for (size_t i = 0; i < count; ++i) {
- jint v1 = get_unaligned<jint>(src++);
- jint v2 = get_unaligned<jint>(src++);
- put_unaligned<jint>(dst++, bswap_32(v2));
- put_unaligned<jint>(dst++, bswap_32(v1));
- }
+ for (size_t i = 0; i < count; ++i) {
+ jint v1 = get_unaligned<jint>(src++);
+ jint v2 = get_unaligned<jint>(src++);
+ put_unaligned<jint>(dst++, bswap_32(v2));
+ put_unaligned<jint>(dst++, bswap_32(v1));
}
}
@@ -260,39 +208,27 @@ static void Memory_pokeShortArray(JNIEnv* env, jclass, jlong dstAddress, jshortA
}
static jshort Memory_peekShortNative(JNIEnv*, jclass, jlong srcAddress) {
- return *cast<const jshort*>(srcAddress);
+ return get_unaligned<jshort>(cast<const jshort*>(srcAddress));
}
static void Memory_pokeShortNative(JNIEnv*, jclass, jlong dstAddress, jshort value) {
- *cast<jshort*>(dstAddress) = value;
+ put_unaligned<jshort>(cast<jshort*>(dstAddress), value);
}
static jint Memory_peekIntNative(JNIEnv*, jclass, jlong srcAddress) {
- return *cast<const jint*>(srcAddress);
+ return get_unaligned<jint>(cast<const jint*>(srcAddress));
}
static void Memory_pokeIntNative(JNIEnv*, jclass, jlong dstAddress, jint value) {
- *cast<jint*>(dstAddress) = value;
+ put_unaligned<jint>(cast<jint*>(dstAddress), value);
}
static jlong Memory_peekLongNative(JNIEnv*, jclass, jlong srcAddress) {
- jlong result;
- const jlong* src = cast<const jlong*>(srcAddress);
- if ((srcAddress & LONG_ALIGNMENT_MASK) == 0) {
- result = *src;
- } else {
- result = get_unaligned<jlong>(src);
- }
- return result;
+ return get_unaligned<jlong>(cast<const jlong*>(srcAddress));
}
static void Memory_pokeLongNative(JNIEnv*, jclass, jlong dstAddress, jlong value) {
- jlong* dst = cast<jlong*>(dstAddress);
- if ((dstAddress & LONG_ALIGNMENT_MASK) == 0) {
- *dst = value;
- } else {
- put_unaligned<jlong>(dst, value);
- }
+ put_unaligned<jlong>(cast<jlong*>(dstAddress), value);
}
static void unsafeBulkCopy(jbyte* dst, const jbyte* src, jint byteCount,
diff --git a/luni/src/main/native/libcore_io_Posix.cpp b/luni/src/main/native/libcore_io_Posix.cpp
index 7e9b22e..99b76f9 100644
--- a/luni/src/main/native/libcore_io_Posix.cpp
+++ b/luni/src/main/native/libcore_io_Posix.cpp
@@ -25,20 +25,20 @@
#include "NetworkUtilities.h"
#include "Portability.h"
#include "readlink.h"
-#include "../../bionic/libc/dns/include/resolv_netid.h" // For android_getaddrinfofornet.
#include "ScopedBytes.h"
#include "ScopedLocalRef.h"
#include "ScopedPrimitiveArray.h"
#include "ScopedUtfChars.h"
#include "toStringArray.h"
-#include "UniquePtr.h"
#include <arpa/inet.h>
#include <errno.h>
#include <fcntl.h>
+#include <linux/rtnetlink.h>
#include <net/if.h>
#include <netdb.h>
#include <netinet/in.h>
+#include <netpacket/packet.h>
#include <poll.h>
#include <pwd.h>
#include <signal.h>
@@ -59,9 +59,10 @@
#include <sys/uio.h>
#include <sys/utsname.h>
#include <sys/wait.h>
+#include <sys/xattr.h>
#include <termios.h>
#include <unistd.h>
-
+#include <memory>
#ifndef __unused
#define __unused __attribute__((__unused__))
@@ -79,6 +80,52 @@ struct addrinfo_deleter {
}
};
+static bool isIPv4MappedAddress(const sockaddr *sa) {
+ const sockaddr_in6 *sin6 = reinterpret_cast<const sockaddr_in6*>(sa);
+ return sa != NULL && sa->sa_family == AF_INET6 &&
+ (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr) ||
+ IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)); // We map 0.0.0.0 to ::, so :: is mapped.
+}
+
+/**
+ * Perform a socket operation that specifies an IP address, possibly falling back from specifying
+ * the address as an IPv4-mapped IPv6 address in a struct sockaddr_in6 to specifying it as an IPv4
+ * address in a struct sockaddr_in.
+ *
+ * This is needed because all sockets created by the java.net APIs are IPv6 sockets, and on those
+ * sockets, IPv4 operations use IPv4-mapped addresses stored in a struct sockaddr_in6. But sockets
+ * created using Posix.socket(AF_INET, ...) are IPv4 sockets and only support operations using IPv4
+ * socket addresses structures.
+ */
+#define NET_IPV4_FALLBACK(jni_env, return_type, syscall_name, java_fd, java_addr, port, null_addr_ok, args...) ({ \
+ return_type _rc = -1; \
+ do { \
+ sockaddr_storage _ss; \
+ socklen_t _salen; \
+ if (java_addr == NULL && null_addr_ok) { \
+ /* No IP address specified (e.g., sendto() on a connected socket). */ \
+ _salen = 0; \
+ } else if (!inetAddressToSockaddr(jni_env, java_addr, port, _ss, _salen)) { \
+ /* Invalid socket address, return -1. inetAddressToSockaddr has already thrown. */ \
+ break; \
+ } \
+ sockaddr* _sa = _salen ? reinterpret_cast<sockaddr*>(&_ss) : NULL; \
+ /* inetAddressToSockaddr always returns an IPv6 sockaddr. Assume that java_fd was created \
+ * by Java API calls, which always create IPv6 socket fds, and pass it in as is. */ \
+ _rc = NET_FAILURE_RETRY(jni_env, return_type, syscall_name, java_fd, ##args, _sa, _salen); \
+ if (_rc == -1 && errno == EAFNOSUPPORT && _salen && isIPv4MappedAddress(_sa)) { \
+ /* We passed in an IPv4 address in an IPv6 sockaddr and the kernel told us that we got \
+ * the address family wrong. Pass in the same address in an IPv4 sockaddr. */ \
+ jni_env->ExceptionClear(); \
+ if (!inetAddressToSockaddrVerbatim(jni_env, java_addr, port, _ss, _salen)) { \
+ break; \
+ } \
+ _sa = reinterpret_cast<sockaddr*>(&_ss); \
+ _rc = NET_FAILURE_RETRY(jni_env, return_type, syscall_name, java_fd, ##args, _sa, _salen); \
+ } \
+ } while (0); \
+ _rc; }) \
+
/**
* Used to retry networking system calls that can be interrupted with a signal. Unlike
* TEMP_FAILURE_RETRY, this also handles the case where
@@ -150,6 +197,9 @@ struct addrinfo_deleter {
} while (_rc == -1); /* && _syscallErrno == EINTR && !_wasSignaled */ \
_rc; })
+#define NULL_ADDR_OK true
+#define NULL_ADDR_FORBIDDEN false
+
static void throwException(JNIEnv* env, jclass exceptionClass, jmethodID ctor3, jmethodID ctor2,
const char* functionName, int error) {
jthrowable cause = NULL;
@@ -268,14 +318,43 @@ private:
};
static jobject makeSocketAddress(JNIEnv* env, const sockaddr_storage& ss) {
- jint port;
- jobject inetAddress = sockaddrToInetAddress(env, ss, &port);
- if (inetAddress == NULL) {
- return NULL;
- }
- static jmethodID ctor = env->GetMethodID(JniConstants::inetSocketAddressClass, "<init>",
- "(Ljava/net/InetAddress;I)V");
- return env->NewObject(JniConstants::inetSocketAddressClass, ctor, inetAddress, port);
+ if (ss.ss_family == AF_INET || ss.ss_family == AF_INET6 || ss.ss_family == AF_UNIX) {
+ jint port;
+ jobject inetAddress = sockaddrToInetAddress(env, ss, &port);
+ if (inetAddress == NULL) {
+ return NULL; // Exception already thrown.
+ }
+ static jmethodID ctor = env->GetMethodID(JniConstants::inetSocketAddressClass,
+ "<init>", "(Ljava/net/InetAddress;I)V");
+ return env->NewObject(JniConstants::inetSocketAddressClass, ctor, inetAddress, port);
+ } else if (ss.ss_family == AF_NETLINK) {
+ const struct sockaddr_nl* nl_addr = reinterpret_cast<const struct sockaddr_nl*>(&ss);
+ static jmethodID ctor = env->GetMethodID(JniConstants::netlinkSocketAddressClass,
+ "<init>", "(II)V");
+ return env->NewObject(JniConstants::netlinkSocketAddressClass, ctor,
+ static_cast<jint>(nl_addr->nl_pid),
+ static_cast<jint>(nl_addr->nl_groups));
+ } else if (ss.ss_family == AF_PACKET) {
+ const struct sockaddr_ll* sll = reinterpret_cast<const struct sockaddr_ll*>(&ss);
+ static jmethodID ctor = env->GetMethodID(JniConstants::packetSocketAddressClass,
+ "<init>", "(SISB[B)V");
+ ScopedLocalRef<jbyteArray> byteArray(env, env->NewByteArray(sll->sll_halen));
+ if (byteArray.get() == NULL) {
+ return NULL;
+ }
+ env->SetByteArrayRegion(byteArray.get(), 0, sll->sll_halen,
+ reinterpret_cast<const jbyte*>(sll->sll_addr));
+ jobject packetSocketAddress = env->NewObject(JniConstants::packetSocketAddressClass, ctor,
+ static_cast<jshort>(ntohs(sll->sll_protocol)),
+ static_cast<jint>(sll->sll_ifindex),
+ static_cast<jshort>(sll->sll_hatype),
+ static_cast<jbyte>(sll->sll_pkttype),
+ byteArray.get());
+ return packetSocketAddress;
+ }
+ jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException", "unsupported ss_family: %d",
+ ss.ss_family);
+ return NULL;
}
static jobject makeStructPasswd(JNIEnv* env, const struct passwd& pw) {
@@ -386,6 +465,93 @@ static bool fillInetSocketAddress(JNIEnv* env, jint rc, jobject javaInetSocketAd
return true;
}
+static void javaInetSocketAddressToInetAddressAndPort(
+ JNIEnv* env, jobject javaInetSocketAddress, jobject& javaInetAddress, jint& port) {
+ static jfieldID addressFid = env->GetFieldID(
+ JniConstants::inetSocketAddressClass, "addr", "Ljava/net/InetAddress;");
+ static jfieldID portFid = env->GetFieldID(JniConstants::inetSocketAddressClass, "port", "I");
+ javaInetAddress = env->GetObjectField(javaInetSocketAddress, addressFid);
+ port = env->GetIntField(javaInetSocketAddress, portFid);
+}
+
+static bool javaInetSocketAddressToSockaddr(
+ JNIEnv* env, jobject javaSocketAddress, sockaddr_storage& ss, socklen_t& sa_len) {
+ jobject javaInetAddress;
+ jint port;
+ javaInetSocketAddressToInetAddressAndPort(env, javaSocketAddress, javaInetAddress, port);
+ return inetAddressToSockaddr(env, javaInetAddress, port, ss, sa_len);
+}
+
+static bool javaNetlinkSocketAddressToSockaddr(
+ JNIEnv* env, jobject javaSocketAddress, sockaddr_storage& ss, socklen_t& sa_len) {
+ static jfieldID nlPidFid = env->GetFieldID(
+ JniConstants::netlinkSocketAddressClass, "nlPortId", "I");
+ static jfieldID nlGroupsFid = env->GetFieldID(
+ JniConstants::netlinkSocketAddressClass, "nlGroupsMask", "I");
+
+ sockaddr_nl *nlAddr = reinterpret_cast<sockaddr_nl *>(&ss);
+ nlAddr->nl_family = AF_NETLINK;
+ nlAddr->nl_pid = env->GetIntField(javaSocketAddress, nlPidFid);
+ nlAddr->nl_groups = env->GetIntField(javaSocketAddress, nlGroupsFid);
+ sa_len = sizeof(sockaddr_nl);
+ return true;
+}
+
+static bool javaPacketSocketAddressToSockaddr(
+ JNIEnv* env, jobject javaSocketAddress, sockaddr_storage& ss, socklen_t& sa_len) {
+ static jfieldID protocolFid = env->GetFieldID(
+ JniConstants::packetSocketAddressClass, "sll_protocol", "S");
+ static jfieldID ifindexFid = env->GetFieldID(
+ JniConstants::packetSocketAddressClass, "sll_ifindex", "I");
+ static jfieldID hatypeFid = env->GetFieldID(
+ JniConstants::packetSocketAddressClass, "sll_hatype", "S");
+ static jfieldID pkttypeFid = env->GetFieldID(
+ JniConstants::packetSocketAddressClass, "sll_pkttype", "B");
+ static jfieldID addrFid = env->GetFieldID(
+ JniConstants::packetSocketAddressClass, "sll_addr", "[B");
+
+ sockaddr_ll *sll = reinterpret_cast<sockaddr_ll *>(&ss);
+ sll->sll_family = AF_PACKET;
+ sll->sll_protocol = htons(env->GetShortField(javaSocketAddress, protocolFid));
+ sll->sll_ifindex = env->GetIntField(javaSocketAddress, ifindexFid);
+ sll->sll_hatype = env->GetShortField(javaSocketAddress, hatypeFid);
+ sll->sll_pkttype = env->GetByteField(javaSocketAddress, pkttypeFid);
+
+ jbyteArray sllAddr = (jbyteArray) env->GetObjectField(javaSocketAddress, addrFid);
+ if (sllAddr == NULL) {
+ sll->sll_halen = 0;
+ memset(&sll->sll_addr, 0, sizeof(sll->sll_addr));
+ } else {
+ jsize len = env->GetArrayLength(sllAddr);
+ if ((size_t) len > sizeof(sll->sll_addr)) {
+ len = sizeof(sll->sll_addr);
+ }
+ sll->sll_halen = len;
+ env->GetByteArrayRegion(sllAddr, 0, len, (jbyte*) sll->sll_addr);
+ }
+ sa_len = sizeof(sockaddr_ll);
+ return true;
+}
+
+static bool javaSocketAddressToSockaddr(
+ JNIEnv* env, jobject javaSocketAddress, sockaddr_storage& ss, socklen_t& sa_len) {
+ if (javaSocketAddress == NULL) {
+ jniThrowNullPointerException(env, NULL);
+ return false;
+ }
+
+ if (env->IsInstanceOf(javaSocketAddress, JniConstants::netlinkSocketAddressClass)) {
+ return javaNetlinkSocketAddressToSockaddr(env, javaSocketAddress, ss, sa_len);
+ } else if (env->IsInstanceOf(javaSocketAddress, JniConstants::inetSocketAddressClass)) {
+ return javaInetSocketAddressToSockaddr(env, javaSocketAddress, ss, sa_len);
+ } else if (env->IsInstanceOf(javaSocketAddress, JniConstants::packetSocketAddressClass)) {
+ return javaPacketSocketAddressToSockaddr(env, javaSocketAddress, ss, sa_len);
+ }
+ jniThrowException(env, "java/lang/UnsupportedOperationException",
+ "unsupported SocketAddress subclass");
+ return false;
+}
+
static jobject doStat(JNIEnv* env, jstring javaPath, bool isLstat) {
ScopedUtfChars path(env, javaPath);
if (path.c_str() == NULL) {
@@ -446,7 +612,7 @@ private:
}
JNIEnv* mEnv;
- UniquePtr<char[]> mBuffer;
+ std::unique_ptr<char[]> mBuffer;
size_t mBufferSize;
struct passwd mPwd;
struct passwd* mResult;
@@ -479,11 +645,18 @@ static jboolean Posix_access(JNIEnv* env, jobject, jstring javaPath, jint mode)
}
static void Posix_bind(JNIEnv* env, jobject, jobject javaFd, jobject javaAddress, jint port) {
+ // We don't need the return value because we'll already have thrown.
+ (void) NET_IPV4_FALLBACK(env, int, bind, javaFd, javaAddress, port, NULL_ADDR_FORBIDDEN);
+}
+
+static void Posix_bindSocketAddress(
+ JNIEnv* env, jobject, jobject javaFd, jobject javaSocketAddress) {
sockaddr_storage ss;
socklen_t sa_len;
- if (!inetAddressToSockaddr(env, javaAddress, port, ss, sa_len)) {
- return;
+ if (!javaSocketAddressToSockaddr(env, javaSocketAddress, ss, sa_len)) {
+ return; // Exception already thrown.
}
+
const sockaddr* sa = reinterpret_cast<const sockaddr*>(&ss);
// We don't need the return value because we'll already have thrown.
(void) NET_FAILURE_RETRY(env, int, bind, javaFd, sa, sa_len);
@@ -518,11 +691,17 @@ static void Posix_close(JNIEnv* env, jobject, jobject javaFd) {
}
static void Posix_connect(JNIEnv* env, jobject, jobject javaFd, jobject javaAddress, jint port) {
+ (void) NET_IPV4_FALLBACK(env, int, connect, javaFd, javaAddress, port, NULL_ADDR_FORBIDDEN);
+}
+
+static void Posix_connectSocketAddress(
+ JNIEnv* env, jobject, jobject javaFd, jobject javaSocketAddress) {
sockaddr_storage ss;
socklen_t sa_len;
- if (!inetAddressToSockaddr(env, javaAddress, port, ss, sa_len)) {
- return;
+ if (!javaSocketAddressToSockaddr(env, javaSocketAddress, ss, sa_len)) {
+ return; // Exception already thrown.
}
+
const sockaddr* sa = reinterpret_cast<const sockaddr*>(&ss);
// We don't need the return value because we'll already have thrown.
(void) NET_FAILURE_RETRY(env, int, connect, javaFd, sa, sa_len);
@@ -553,7 +732,7 @@ static void Posix_execve(JNIEnv* env, jobject, jstring javaFilename, jobjectArra
ExecStrings argv(env, javaArgv);
ExecStrings envp(env, javaEnvp);
- execve(path.c_str(), argv.get(), envp.get());
+ TEMP_FAILURE_RETRY(execve(path.c_str(), argv.get(), envp.get()));
throwErrnoException(env, "execve");
}
@@ -565,7 +744,7 @@ static void Posix_execv(JNIEnv* env, jobject, jstring javaFilename, jobjectArray
}
ExecStrings argv(env, javaArgv);
- execv(path.c_str(), argv.get());
+ TEMP_FAILURE_RETRY(execv(path.c_str(), argv.get()));
throwErrnoException(env, "execv");
}
@@ -580,16 +759,6 @@ static void Posix_fchown(JNIEnv* env, jobject, jobject javaFd, jint uid, jint gi
throwIfMinusOne(env, "fchown", TEMP_FAILURE_RETRY(fchown(fd, uid, gid)));
}
-static jint Posix_fcntlVoid(JNIEnv* env, jobject, jobject javaFd, jint cmd) {
- int fd = jniGetFDFromFileDescriptor(env, javaFd);
- return throwIfMinusOne(env, "fcntl", TEMP_FAILURE_RETRY(fcntl(fd, cmd)));
-}
-
-static jint Posix_fcntlLong(JNIEnv* env, jobject, jobject javaFd, jint cmd, jlong arg) {
- int fd = jniGetFDFromFileDescriptor(env, javaFd);
- return throwIfMinusOne(env, "fcntl", TEMP_FAILURE_RETRY(fcntl(fd, cmd, arg)));
-}
-
static jint Posix_fcntlFlock(JNIEnv* env, jobject, jobject javaFd, jint cmd, jobject javaFlock) {
static jfieldID typeFid = env->GetFieldID(JniConstants::structFlockClass, "l_type", "S");
static jfieldID whenceFid = env->GetFieldID(JniConstants::structFlockClass, "l_whence", "S");
@@ -616,6 +785,16 @@ static jint Posix_fcntlFlock(JNIEnv* env, jobject, jobject javaFd, jint cmd, job
return rc;
}
+static jint Posix_fcntlInt(JNIEnv* env, jobject, jobject javaFd, jint cmd, jint arg) {
+ int fd = jniGetFDFromFileDescriptor(env, javaFd);
+ return throwIfMinusOne(env, "fcntl", TEMP_FAILURE_RETRY(fcntl(fd, cmd, arg)));
+}
+
+static jint Posix_fcntlVoid(JNIEnv* env, jobject, jobject javaFd, jint cmd) {
+ int fd = jniGetFDFromFileDescriptor(env, javaFd);
+ return throwIfMinusOne(env, "fcntl", TEMP_FAILURE_RETRY(fcntl(fd, cmd)));
+}
+
static void Posix_fdatasync(JNIEnv* env, jobject, jobject javaFd) {
int fd = jniGetFDFromFileDescriptor(env, javaFd);
throwIfMinusOne(env, "fdatasync", TEMP_FAILURE_RETRY(fdatasync(fd)));
@@ -679,7 +858,7 @@ static jobjectArray Posix_android_getaddrinfo(JNIEnv* env, jobject, jstring java
addrinfo* addressList = NULL;
errno = 0;
int rc = android_getaddrinfofornet(node.c_str(), NULL, &hints, netId, 0, &addressList);
- UniquePtr<addrinfo, addrinfo_deleter> addressListDeleter(addressList);
+ std::unique_ptr<addrinfo, addrinfo_deleter> addressListDeleter(addressList);
if (rc != 0) {
throwGaiException(env, "android_getaddrinfo", rc);
return NULL;
@@ -765,12 +944,16 @@ static jobject Posix_getpeername(JNIEnv* env, jobject, jobject javaFd) {
return doGetSockName(env, javaFd, false);
}
+static jint Posix_getpgid(JNIEnv* env, jobject, jint pid) {
+ return throwIfMinusOne(env, "getpgid", TEMP_FAILURE_RETRY(getpgid(pid)));
+}
+
static jint Posix_getpid(JNIEnv*, jobject) {
- return getpid();
+ return TEMP_FAILURE_RETRY(getpid());
}
static jint Posix_getppid(JNIEnv*, jobject) {
- return getppid();
+ return TEMP_FAILURE_RETRY(getppid());
}
static jobject Posix_getpwnam(JNIEnv* env, jobject, jstring javaName) {
@@ -868,8 +1051,9 @@ static jint Posix_gettid(JNIEnv* env __unused, jobject) {
return 0;
}
return static_cast<jint>(owner);
+#elif defined(__BIONIC__)
+ return TEMP_FAILURE_RETRY(gettid());
#else
- // Neither bionic nor glibc exposes gettid(2).
return syscall(__NR_gettid);
#endif
}
@@ -878,6 +1062,28 @@ static jint Posix_getuid(JNIEnv*, jobject) {
return getuid();
}
+static jint Posix_getxattr(JNIEnv* env, jobject, jstring javaPath,
+ jstring javaName, jbyteArray javaOutValue) {
+ ScopedUtfChars path(env, javaPath);
+ if (path.c_str() == NULL) {
+ return -1;
+ }
+ ScopedUtfChars name(env, javaName);
+ if (name.c_str() == NULL) {
+ return -1;
+ }
+ ScopedBytesRW outValue(env, javaOutValue);
+ if (outValue.get() == NULL) {
+ return -1;
+ }
+ size_t outValueLength = env->GetArrayLength(javaOutValue);
+ ssize_t size = getxattr(path.c_str(), name.c_str(), outValue.get(), outValueLength);
+ if (size < 0) {
+ throwErrnoException(env, "getxattr");
+ }
+ return size;
+}
+
static jstring Posix_if_indextoname(JNIEnv* env, jobject, jint index) {
char buf[IF_NAMESIZE];
char* name = if_indextoname(index, buf);
@@ -1036,9 +1242,13 @@ static jobject Posix_open(JNIEnv* env, jobject, jstring javaPath, jint flags, ji
return fd != -1 ? jniCreateFileDescriptor(env, fd) : NULL;
}
-static jobjectArray Posix_pipe(JNIEnv* env, jobject) {
+static jobjectArray Posix_pipe2(JNIEnv* env, jobject, jint flags __unused) {
+#ifdef __APPLE__
+ jniThrowException(env, "java/lang/UnsupportedOperationException", "no pipe2 on Mac OS");
+ return NULL;
+#else
int fds[2];
- throwIfMinusOne(env, "pipe", TEMP_FAILURE_RETRY(pipe(&fds[0])));
+ throwIfMinusOne(env, "pipe2", TEMP_FAILURE_RETRY(pipe2(&fds[0], flags)));
jobjectArray result = env->NewObjectArray(2, JniConstants::fileDescriptorClass, NULL);
if (result == NULL) {
return NULL;
@@ -1054,6 +1264,7 @@ static jobjectArray Posix_pipe(JNIEnv* env, jobject) {
}
}
return result;
+#endif
}
static jint Posix_poll(JNIEnv* env, jobject, jobjectArray javaStructs, jint timeoutMs) {
@@ -1063,7 +1274,7 @@ static jint Posix_poll(JNIEnv* env, jobject, jobjectArray javaStructs, jint time
// Turn the Java android.system.StructPollfd[] into a C++ struct pollfd[].
size_t arrayLength = env->GetArrayLength(javaStructs);
- UniquePtr<struct pollfd[]> fds(new struct pollfd[arrayLength]);
+ std::unique_ptr<struct pollfd[]> fds(new struct pollfd[arrayLength]);
memset(fds.get(), 0, sizeof(struct pollfd) * arrayLength);
size_t count = 0; // Some trailing array elements may be irrelevant. (See below.)
for (size_t i = 0; i < arrayLength; ++i) {
@@ -1084,7 +1295,40 @@ static jint Posix_poll(JNIEnv* env, jobject, jobjectArray javaStructs, jint time
for (size_t i = 0; i < count; ++i) {
monitors.push_back(new AsynchronousCloseMonitor(fds[i].fd));
}
- int rc = poll(fds.get(), count, timeoutMs);
+
+ int rc;
+ while (true) {
+ timespec before;
+ clock_gettime(CLOCK_MONOTONIC, &before);
+
+ rc = poll(fds.get(), count, timeoutMs);
+ if (rc >= 0 || errno != EINTR) {
+ break;
+ }
+
+ // We got EINTR. Work out how much of the original timeout is still left.
+ if (timeoutMs > 0) {
+ timespec now;
+ clock_gettime(CLOCK_MONOTONIC, &now);
+
+ timespec diff;
+ diff.tv_sec = now.tv_sec - before.tv_sec;
+ diff.tv_nsec = now.tv_nsec - before.tv_nsec;
+ if (diff.tv_nsec < 0) {
+ --diff.tv_sec;
+ diff.tv_nsec += 1000000000;
+ }
+
+ jint diffMs = diff.tv_sec * 1000 + diff.tv_nsec / 1000000;
+ if (diffMs >= timeoutMs) {
+ rc = 0; // We have less than 1ms left anyway, so just time out.
+ break;
+ }
+
+ timeoutMs -= diffMs;
+ }
+ }
+
for (size_t i = 0; i < monitors.size(); ++i) {
delete monitors[i];
}
@@ -1111,7 +1355,8 @@ static void Posix_posix_fallocate(JNIEnv* env, jobject, jobject javaFd __unused,
"fallocate doesn't exist on a Mac");
#else
int fd = jniGetFDFromFileDescriptor(env, javaFd);
- errno = TEMP_FAILURE_RETRY(posix_fallocate64(fd, offset, length));
+ while ((errno = posix_fallocate64(fd, offset, length)) == EINTR) {
+ }
if (errno != 0) {
throwErrnoException(env, "posix_fallocate");
}
@@ -1124,9 +1369,11 @@ static jint Posix_prctl(JNIEnv* env, jobject, jint option __unused, jlong arg2 _
jniThrowException(env, "java/lang/UnsupportedOperationException", "prctl doesn't exist on a Mac");
return 0;
#else
- int result = prctl(static_cast<int>(option),
- static_cast<unsigned long>(arg2), static_cast<unsigned long>(arg3),
- static_cast<unsigned long>(arg4), static_cast<unsigned long>(arg5));
+ int result = TEMP_FAILURE_RETRY(prctl(static_cast<int>(option),
+ static_cast<unsigned long>(arg2),
+ static_cast<unsigned long>(arg3),
+ static_cast<unsigned long>(arg4),
+ static_cast<unsigned long>(arg5)));
return throwIfMinusOne(env, "prctl", result);
#endif
}
@@ -1200,6 +1447,22 @@ static void Posix_remove(JNIEnv* env, jobject, jstring javaPath) {
throwIfMinusOne(env, "remove", TEMP_FAILURE_RETRY(remove(path.c_str())));
}
+static void Posix_removexattr(JNIEnv* env, jobject, jstring javaPath, jstring javaName) {
+ ScopedUtfChars path(env, javaPath);
+ if (path.c_str() == NULL) {
+ return;
+ }
+ ScopedUtfChars name(env, javaName);
+ if (name.c_str() == NULL) {
+ return;
+ }
+
+ int res = removexattr(path.c_str(), name.c_str());
+ if (res < 0) {
+ throwErrnoException(env, "removexattr");
+ }
+}
+
static void Posix_rename(JNIEnv* env, jobject, jstring javaOldPath, jstring javaNewPath) {
ScopedUtfChars oldPath(env, javaOldPath);
if (oldPath.c_str() == NULL) {
@@ -1235,13 +1498,35 @@ static jint Posix_sendtoBytes(JNIEnv* env, jobject, jobject javaFd, jobject java
if (bytes.get() == NULL) {
return -1;
}
+
+ return NET_IPV4_FALLBACK(env, ssize_t, sendto, javaFd, javaInetAddress, port,
+ NULL_ADDR_OK, bytes.get() + byteOffset, byteCount, flags);
+}
+
+static jint Posix_sendtoBytesSocketAddress(JNIEnv* env, jobject, jobject javaFd, jobject javaBytes, jint byteOffset, jint byteCount, jint flags, jobject javaSocketAddress) {
+ if (env->IsInstanceOf(javaSocketAddress, JniConstants::inetSocketAddressClass)) {
+ // Use the InetAddress version so we get the benefit of NET_IPV4_FALLBACK.
+ jobject javaInetAddress;
+ jint port;
+ javaInetSocketAddressToInetAddressAndPort(env, javaSocketAddress, javaInetAddress, port);
+ return Posix_sendtoBytes(env, NULL, javaFd, javaBytes, byteOffset, byteCount, flags,
+ javaInetAddress, port);
+ }
+
+ ScopedBytesRO bytes(env, javaBytes);
+ if (bytes.get() == NULL) {
+ return -1;
+ }
+
sockaddr_storage ss;
- socklen_t sa_len = 0;
- if (javaInetAddress != NULL && !inetAddressToSockaddr(env, javaInetAddress, port, ss, sa_len)) {
+ socklen_t sa_len;
+ if (!javaSocketAddressToSockaddr(env, javaSocketAddress, ss, sa_len)) {
return -1;
}
- const sockaddr* to = (javaInetAddress != NULL) ? reinterpret_cast<const sockaddr*>(&ss) : NULL;
- return NET_FAILURE_RETRY(env, ssize_t, sendto, javaFd, bytes.get() + byteOffset, byteCount, flags, to, sa_len);
+
+ const sockaddr* sa = reinterpret_cast<const sockaddr*>(&ss);
+ // We don't need the return value because we'll already have thrown.
+ return NET_FAILURE_RETRY(env, ssize_t, sendto, javaFd, bytes.get() + byteOffset, byteCount, flags, sa, sa_len);
}
static void Posix_setegid(JNIEnv* env, jobject, jint egid) {
@@ -1268,6 +1553,18 @@ static void Posix_setgid(JNIEnv* env, jobject, jint gid) {
throwIfMinusOne(env, "setgid", TEMP_FAILURE_RETRY(setgid(gid)));
}
+static void Posix_setpgid(JNIEnv* env, jobject, jint pid, int pgid) {
+ throwIfMinusOne(env, "setpgid", TEMP_FAILURE_RETRY(setpgid(pid, pgid)));
+}
+
+static void Posix_setregid(JNIEnv* env, jobject, jint rgid, int egid) {
+ throwIfMinusOne(env, "setregid", TEMP_FAILURE_RETRY(setregid(rgid, egid)));
+}
+
+static void Posix_setreuid(JNIEnv* env, jobject, jint ruid, int euid) {
+ throwIfMinusOne(env, "setreuid", TEMP_FAILURE_RETRY(setreuid(ruid, euid)));
+}
+
static jint Posix_setsid(JNIEnv* env, jobject) {
return throwIfMinusOne(env, "setsid", TEMP_FAILURE_RETRY(setsid()));
}
@@ -1406,12 +1703,36 @@ static void Posix_setuid(JNIEnv* env, jobject, jint uid) {
throwIfMinusOne(env, "setuid", TEMP_FAILURE_RETRY(setuid(uid)));
}
+static void Posix_setxattr(JNIEnv* env, jobject, jstring javaPath, jstring javaName,
+ jbyteArray javaValue, jint flags) {
+ ScopedUtfChars path(env, javaPath);
+ if (path.c_str() == NULL) {
+ return;
+ }
+ ScopedUtfChars name(env, javaName);
+ if (name.c_str() == NULL) {
+ return;
+ }
+ ScopedBytesRO value(env, javaValue);
+ if (value.get() == NULL) {
+ return;
+ }
+ size_t valueLength = env->GetArrayLength(javaValue);
+ int res = setxattr(path.c_str(), name.c_str(), value.get(), valueLength, flags);
+ if (res < 0) {
+ throwErrnoException(env, "setxattr");
+ }
+}
+
static void Posix_shutdown(JNIEnv* env, jobject, jobject javaFd, jint how) {
int fd = jniGetFDFromFileDescriptor(env, javaFd);
throwIfMinusOne(env, "shutdown", TEMP_FAILURE_RETRY(shutdown(fd, how)));
}
static jobject Posix_socket(JNIEnv* env, jobject, jint domain, jint type, jint protocol) {
+ if (domain == AF_PACKET) {
+ protocol = htons(protocol); // Packet sockets specify the protocol in host byte order.
+ }
int fd = throwIfMinusOne(env, "socket", TEMP_FAILURE_RETRY(socket(domain, type, protocol)));
return fd != -1 ? jniCreateFileDescriptor(env, fd) : NULL;
}
@@ -1531,15 +1852,20 @@ static jint Posix_writev(JNIEnv* env, jobject, jobject javaFd, jobjectArray buff
return IO_FAILURE_RETRY(env, ssize_t, writev, javaFd, ioVec.get(), ioVec.size());
}
+#define NATIVE_METHOD_OVERLOAD(className, functionName, signature, variant) \
+ { #functionName, signature, reinterpret_cast<void*>(className ## _ ## functionName ## variant) }
+
static JNINativeMethod gMethods[] = {
NATIVE_METHOD(Posix, accept, "(Ljava/io/FileDescriptor;Ljava/net/InetSocketAddress;)Ljava/io/FileDescriptor;"),
NATIVE_METHOD(Posix, access, "(Ljava/lang/String;I)Z"),
NATIVE_METHOD(Posix, android_getaddrinfo, "(Ljava/lang/String;Landroid/system/StructAddrinfo;I)[Ljava/net/InetAddress;"),
NATIVE_METHOD(Posix, bind, "(Ljava/io/FileDescriptor;Ljava/net/InetAddress;I)V"),
+ NATIVE_METHOD_OVERLOAD(Posix, bind, "(Ljava/io/FileDescriptor;Ljava/net/SocketAddress;)V", SocketAddress),
NATIVE_METHOD(Posix, chmod, "(Ljava/lang/String;I)V"),
NATIVE_METHOD(Posix, chown, "(Ljava/lang/String;II)V"),
NATIVE_METHOD(Posix, close, "(Ljava/io/FileDescriptor;)V"),
NATIVE_METHOD(Posix, connect, "(Ljava/io/FileDescriptor;Ljava/net/InetAddress;I)V"),
+ NATIVE_METHOD_OVERLOAD(Posix, connect, "(Ljava/io/FileDescriptor;Ljava/net/SocketAddress;)V", SocketAddress),
NATIVE_METHOD(Posix, dup, "(Ljava/io/FileDescriptor;)Ljava/io/FileDescriptor;"),
NATIVE_METHOD(Posix, dup2, "(Ljava/io/FileDescriptor;I)Ljava/io/FileDescriptor;"),
NATIVE_METHOD(Posix, environ, "()[Ljava/lang/String;"),
@@ -1547,9 +1873,9 @@ static JNINativeMethod gMethods[] = {
NATIVE_METHOD(Posix, execve, "(Ljava/lang/String;[Ljava/lang/String;[Ljava/lang/String;)V"),
NATIVE_METHOD(Posix, fchmod, "(Ljava/io/FileDescriptor;I)V"),
NATIVE_METHOD(Posix, fchown, "(Ljava/io/FileDescriptor;II)V"),
- NATIVE_METHOD(Posix, fcntlVoid, "(Ljava/io/FileDescriptor;I)I"),
- NATIVE_METHOD(Posix, fcntlLong, "(Ljava/io/FileDescriptor;IJ)I"),
NATIVE_METHOD(Posix, fcntlFlock, "(Ljava/io/FileDescriptor;ILandroid/system/StructFlock;)I"),
+ NATIVE_METHOD(Posix, fcntlInt, "(Ljava/io/FileDescriptor;II)I"),
+ NATIVE_METHOD(Posix, fcntlVoid, "(Ljava/io/FileDescriptor;I)I"),
NATIVE_METHOD(Posix, fdatasync, "(Ljava/io/FileDescriptor;)V"),
NATIVE_METHOD(Posix, fstat, "(Ljava/io/FileDescriptor;)Landroid/system/StructStat;"),
NATIVE_METHOD(Posix, fstatvfs, "(Ljava/io/FileDescriptor;)Landroid/system/StructStatVfs;"),
@@ -1562,6 +1888,7 @@ static JNINativeMethod gMethods[] = {
NATIVE_METHOD(Posix, getenv, "(Ljava/lang/String;)Ljava/lang/String;"),
NATIVE_METHOD(Posix, getnameinfo, "(Ljava/net/InetAddress;I)Ljava/lang/String;"),
NATIVE_METHOD(Posix, getpeername, "(Ljava/io/FileDescriptor;)Ljava/net/SocketAddress;"),
+ NATIVE_METHOD(Posix, getpgid, "(I)I"),
NATIVE_METHOD(Posix, getpid, "()I"),
NATIVE_METHOD(Posix, getppid, "()I"),
NATIVE_METHOD(Posix, getpwnam, "(Ljava/lang/String;)Landroid/system/StructPasswd;"),
@@ -1575,6 +1902,7 @@ static JNINativeMethod gMethods[] = {
NATIVE_METHOD(Posix, getsockoptUcred, "(Ljava/io/FileDescriptor;II)Landroid/system/StructUcred;"),
NATIVE_METHOD(Posix, gettid, "()I"),
NATIVE_METHOD(Posix, getuid, "()I"),
+ NATIVE_METHOD(Posix, getxattr, "(Ljava/lang/String;Ljava/lang/String;[B)I"),
NATIVE_METHOD(Posix, if_indextoname, "(I)Ljava/lang/String;"),
NATIVE_METHOD(Posix, inet_pton, "(ILjava/lang/String;)Ljava/net/InetAddress;"),
NATIVE_METHOD(Posix, ioctlInetAddress, "(Ljava/io/FileDescriptor;ILjava/lang/String;)Ljava/net/InetAddress;"),
@@ -1595,7 +1923,7 @@ static JNINativeMethod gMethods[] = {
NATIVE_METHOD(Posix, munlock, "(JJ)V"),
NATIVE_METHOD(Posix, munmap, "(JJ)V"),
NATIVE_METHOD(Posix, open, "(Ljava/lang/String;II)Ljava/io/FileDescriptor;"),
- NATIVE_METHOD(Posix, pipe, "()[Ljava/io/FileDescriptor;"),
+ NATIVE_METHOD(Posix, pipe2, "(I)[Ljava/io/FileDescriptor;"),
NATIVE_METHOD(Posix, poll, "([Landroid/system/StructPollfd;I)I"),
NATIVE_METHOD(Posix, posix_fallocate, "(Ljava/io/FileDescriptor;JJ)V"),
NATIVE_METHOD(Posix, prctl, "(IJJJJ)I"),
@@ -1606,13 +1934,18 @@ static JNINativeMethod gMethods[] = {
NATIVE_METHOD(Posix, readv, "(Ljava/io/FileDescriptor;[Ljava/lang/Object;[I[I)I"),
NATIVE_METHOD(Posix, recvfromBytes, "(Ljava/io/FileDescriptor;Ljava/lang/Object;IIILjava/net/InetSocketAddress;)I"),
NATIVE_METHOD(Posix, remove, "(Ljava/lang/String;)V"),
+ NATIVE_METHOD(Posix, removexattr, "(Ljava/lang/String;Ljava/lang/String;)V"),
NATIVE_METHOD(Posix, rename, "(Ljava/lang/String;Ljava/lang/String;)V"),
NATIVE_METHOD(Posix, sendfile, "(Ljava/io/FileDescriptor;Ljava/io/FileDescriptor;Landroid/util/MutableLong;J)J"),
NATIVE_METHOD(Posix, sendtoBytes, "(Ljava/io/FileDescriptor;Ljava/lang/Object;IIILjava/net/InetAddress;I)I"),
+ NATIVE_METHOD_OVERLOAD(Posix, sendtoBytes, "(Ljava/io/FileDescriptor;Ljava/lang/Object;IIILjava/net/SocketAddress;)I", SocketAddress),
NATIVE_METHOD(Posix, setegid, "(I)V"),
NATIVE_METHOD(Posix, setenv, "(Ljava/lang/String;Ljava/lang/String;Z)V"),
NATIVE_METHOD(Posix, seteuid, "(I)V"),
NATIVE_METHOD(Posix, setgid, "(I)V"),
+ NATIVE_METHOD(Posix, setpgid, "(II)V"),
+ NATIVE_METHOD(Posix, setregid, "(II)V"),
+ NATIVE_METHOD(Posix, setreuid, "(II)V"),
NATIVE_METHOD(Posix, setsid, "()I"),
NATIVE_METHOD(Posix, setsockoptByte, "(Ljava/io/FileDescriptor;III)V"),
NATIVE_METHOD(Posix, setsockoptIfreq, "(Ljava/io/FileDescriptor;IILjava/lang/String;)V"),
@@ -1623,6 +1956,7 @@ static JNINativeMethod gMethods[] = {
NATIVE_METHOD(Posix, setsockoptLinger, "(Ljava/io/FileDescriptor;IILandroid/system/StructLinger;)V"),
NATIVE_METHOD(Posix, setsockoptTimeval, "(Ljava/io/FileDescriptor;IILandroid/system/StructTimeval;)V"),
NATIVE_METHOD(Posix, setuid, "(I)V"),
+ NATIVE_METHOD(Posix, setxattr, "(Ljava/lang/String;Ljava/lang/String;[BI)V"),
NATIVE_METHOD(Posix, shutdown, "(Ljava/io/FileDescriptor;I)V"),
NATIVE_METHOD(Posix, socket, "(III)Ljava/io/FileDescriptor;"),
NATIVE_METHOD(Posix, socketpair, "(IIILjava/io/FileDescriptor;Ljava/io/FileDescriptor;)V"),
diff --git a/luni/src/main/native/org_apache_harmony_xml_ExpatParser.cpp b/luni/src/main/native/org_apache_harmony_xml_ExpatParser.cpp
index 2ea8806..48defc1 100644
--- a/luni/src/main/native/org_apache_harmony_xml_ExpatParser.cpp
+++ b/luni/src/main/native/org_apache_harmony_xml_ExpatParser.cpp
@@ -24,11 +24,12 @@
#include "ScopedPrimitiveArray.h"
#include "ScopedStringChars.h"
#include "ScopedUtfChars.h"
-#include "UniquePtr.h"
#include "jni.h"
#include "cutils/log.h"
#include "unicode/unistr.h"
+#include <memory>
+
#include <string.h>
#include <libexpat/expat.h>
@@ -253,7 +254,7 @@ static int hashString(const char* s) {
*/
static InternedString* newInternedString(JNIEnv* env, const char* bytes, int hash) {
// Allocate a new wrapper.
- UniquePtr<InternedString> wrapper(new InternedString);
+ std::unique_ptr<InternedString> wrapper(new InternedString);
if (wrapper.get() == NULL) {
jniThrowOutOfMemoryError(env, NULL);
return NULL;
@@ -439,7 +440,7 @@ static size_t fillBuffer(ParsingContext* parsingContext, const char* utf8, int b
return -1;
}
UErrorCode status = U_ZERO_ERROR;
- UnicodeString utf16(UnicodeString::fromUTF8(StringPiece(utf8, byteCount)));
+ icu::UnicodeString utf16(icu::UnicodeString::fromUTF8(icu::StringPiece(utf8, byteCount)));
return utf16.extract(chars.get(), byteCount, status);
}
@@ -962,7 +963,7 @@ static void notationDecl(void* data, const char* name, const char* /*base*/, con
static jlong ExpatParser_initialize(JNIEnv* env, jobject object, jstring javaEncoding,
jboolean processNamespaces) {
// Allocate parsing context.
- UniquePtr<ParsingContext> context(new ParsingContext(object));
+ std::unique_ptr<ParsingContext> context(new ParsingContext(object));
if (context.get() == NULL) {
jniThrowOutOfMemoryError(env, NULL);
return 0;
diff --git a/luni/src/main/native/sub.mk b/luni/src/main/native/sub.mk
index 079ecd2..73ed7cb 100644
--- a/luni/src/main/native/sub.mk
+++ b/luni/src/main/native/sub.mk
@@ -28,7 +28,6 @@ LOCAL_SRC_FILES := \
java_lang_System.cpp \
java_math_NativeBN.cpp \
java_nio_ByteOrder.cpp \
- java_nio_charset_Charsets.cpp \
java_text_Bidi.cpp \
java_util_jar_StrictJarFile.cpp \
java_util_regex_Matcher.cpp \
@@ -38,9 +37,7 @@ LOCAL_SRC_FILES := \
java_util_zip_Deflater.cpp \
java_util_zip_Inflater.cpp \
libcore_icu_AlphabeticIndex.cpp \
- libcore_icu_DateIntervalFormat.cpp \
libcore_icu_ICU.cpp \
- libcore_icu_NativeBreakIterator.cpp \
libcore_icu_NativeCollation.cpp \
libcore_icu_NativeConverter.cpp \
libcore_icu_NativeDecimalFormat.cpp \
@@ -57,13 +54,6 @@ LOCAL_SRC_FILES := \
sun_misc_Unsafe.cpp \
valueOf.cpp \
-LOCAL_C_INCLUDES += \
- external/icu/icu4c/source/common \
- external/icu/icu4c/source/i18n \
- external/openssl/include \
- external/zlib \
- system/core/include \
-
LOCAL_STATIC_LIBRARIES += \
libfdlibm \
diff --git a/luni/src/test/java/com/android/org/bouncycastle/crypto/digests/DigestTest.java b/luni/src/test/java/com/android/org/bouncycastle/crypto/digests/DigestTest.java
index 8708214..fce8507 100644
--- a/luni/src/test/java/com/android/org/bouncycastle/crypto/digests/DigestTest.java
+++ b/luni/src/test/java/com/android/org/bouncycastle/crypto/digests/DigestTest.java
@@ -19,6 +19,7 @@ package com.android.org.bouncycastle.crypto.digests;
import junit.framework.TestCase;
import com.android.org.bouncycastle.crypto.Digest;
import com.android.org.bouncycastle.crypto.ExtendedDigest;
+import tests.util.SummaryStatistics;
/**
* Implements unit tests for our JNI wrapper around OpenSSL. We use the
@@ -36,6 +37,7 @@ public class DigestTest extends TestCase {
* @param newDigest The new digest implementation, provided by OpenSSL
*/
public void doTestMessageDigest(Digest oldDigest, Digest newDigest) {
+ final int WARMUP = 10;
final int ITERATIONS = 100;
byte[] data = new byte[1024];
@@ -54,27 +56,31 @@ public class DigestTest extends TestCase {
data[i] = (byte)i;
}
- long oldTime = 0;
- long newTime = 0;
+ SummaryStatistics oldTime = new SummaryStatistics();
+ SummaryStatistics newTime = new SummaryStatistics();
- for (int j = 0; j < ITERATIONS; j++) {
- long t0 = System.currentTimeMillis();
+ for (int j = 0; j < ITERATIONS + WARMUP; j++) {
+ long t0 = System.nanoTime();
for (int i = 0; i < 4; i++) {
oldDigest.update(data, 0, data.length);
}
int oldLength = oldDigest.doFinal(oldHash, 0);
- long t1 = System.currentTimeMillis();
+ long t1 = System.nanoTime();
- oldTime = oldTime + (t1 - t0);
+ if (j >= WARMUP) {
+ oldTime.add(t1 - t0);
+ }
- long t2 = System.currentTimeMillis();
+ long t2 = System.nanoTime();
for (int i = 0; i < 4; i++) {
newDigest.update(data, 0, data.length);
}
int newLength = newDigest.doFinal(newHash, 0);
- long t3 = System.currentTimeMillis();
+ long t3 = System.nanoTime();
- newTime = newTime + (t3 - t2);
+ if (j >= WARMUP) {
+ newTime.add(t3 - t2);
+ }
assertEquals("Hash sizes must be equal", oldLength, newLength);
@@ -83,10 +89,13 @@ public class DigestTest extends TestCase {
}
}
- System.out.println("Time for " + ITERATIONS + " x old hash processing: " + oldTime + " ms");
- System.out.println("Time for " + ITERATIONS + " x new hash processing: " + newTime + " ms");
+ System.out.println("Time for " + ITERATIONS + " x old hash processing: "
+ + oldTime.toString());
+ System.out.println("Time for " + ITERATIONS + " x new hash processing: "
+ + newTime.toString());
- assertTrue("New hash should be faster", newTime < oldTime);
+ assertTrue("New hash should be faster:\nold=" + oldTime.toString() + "\nnew="
+ + newTime.toString(), newTime.mean() < oldTime.mean());
}
/**
diff --git a/luni/src/test/java/com/android/org/bouncycastle/jce/provider/CertBlacklistTest.java b/luni/src/test/java/com/android/org/bouncycastle/jce/provider/CertBlacklistTest.java
index 8627225..48a175c 100644
--- a/luni/src/test/java/com/android/org/bouncycastle/jce/provider/CertBlacklistTest.java
+++ b/luni/src/test/java/com/android/org/bouncycastle/jce/provider/CertBlacklistTest.java
@@ -401,11 +401,6 @@ public class CertBlacklistTest extends TestCase {
assertEquals(bl, getCurrentSerialBlacklist());
}
- public void testTurkTrustIntermediate1SerialBlacklist() throws Exception {
- CertBlacklist bl = new CertBlacklist();
- assertEquals(bl.isSerialNumberBlackListed(createSerialNumber(TURKTRUST_1)), true);
- }
-
public void testTurkTrustIntermediate1PubkeyBlacklist() throws Exception {
// build the public key
PublicKey pk = createPublicKey(TURKTRUST_1);
@@ -417,11 +412,6 @@ public class CertBlacklistTest extends TestCase {
assertEquals(bl.isPublicKeyBlackListed(pk), true);
}
- public void testTurkTrustIntermediate2SerialBlacklist() throws Exception {
- CertBlacklist bl = new CertBlacklist();
- assertEquals(bl.isSerialNumberBlackListed(createSerialNumber(TURKTRUST_2)), true);
- }
-
public void testTurkTrustIntermediate2PubkeyBlacklist() throws Exception {
// build the public key
PublicKey pk = createPublicKey(TURKTRUST_2);
@@ -431,11 +421,6 @@ public class CertBlacklistTest extends TestCase {
assertEquals(bl.isPublicKeyBlackListed(pk), true);
}
- public void testANSSISerialBlacklist() throws Exception {
- CertBlacklist bl = new CertBlacklist();
- assertEquals(bl.isSerialNumberBlackListed(createSerialNumber(ANSSI)), true);
- }
-
public void testANSSIIntermediatePubkeyBlacklist() throws Exception {
// build the public key
PublicKey pk = createPublicKey(ANSSI);
diff --git a/luni/src/test/java/libcore/dalvik/system/PathClassLoaderTest.java b/luni/src/test/java/libcore/dalvik/system/PathClassLoaderTest.java
index 9e6d8d7..31e8fc7 100644
--- a/luni/src/test/java/libcore/dalvik/system/PathClassLoaderTest.java
+++ b/luni/src/test/java/libcore/dalvik/system/PathClassLoaderTest.java
@@ -17,9 +17,12 @@
package libcore.dalvik.system;
import dalvik.system.PathClassLoader;
+import java.lang.reflect.Method;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
+import java.io.InputStream;
+import libcore.io.Streams;
import junit.framework.TestCase;
public final class PathClassLoaderTest extends TestCase {
@@ -52,6 +55,26 @@ public final class PathClassLoaderTest extends TestCase {
return result;
}
+ public void testAppUseOfPathClassLoader() throws Exception {
+ // Extract loading-test.jar from the resource.
+ ClassLoader pcl = PathClassLoaderTest.class.getClassLoader();
+ File jar = File.createTempFile("loading-test", ".jar");
+ try (InputStream in = pcl.getResourceAsStream("dalvik/system/loading-test.jar");
+ FileOutputStream out = new FileOutputStream(jar)) {
+ Streams.copy(in, out);
+ }
+
+ // Execute code from the jar file using a PathClassLoader.
+ PathClassLoader cl = new PathClassLoader(jar.getPath(), pcl);
+ Class c = cl.loadClass("test.Test1");
+ Method m = c.getMethod("test", (Class[]) null);
+ String result = (String) m.invoke(null, (Object[]) null);
+ assertSame("blort", result);
+
+ // Clean up the extracted jar file.
+ assertTrue(jar.delete());
+ }
+
@Override protected void setUp() throws Exception {
super.setUp();
}
diff --git a/luni/src/test/java/libcore/icu/DateIntervalFormatTest.java b/luni/src/test/java/libcore/icu/DateIntervalFormatTest.java
index 1c1296b..4c22371 100644
--- a/luni/src/test/java/libcore/icu/DateIntervalFormatTest.java
+++ b/luni/src/test/java/libcore/icu/DateIntervalFormatTest.java
@@ -16,10 +16,12 @@
package libcore.icu;
-import java.util.Calendar;
-import java.util.Locale;
-import java.util.TimeZone;
-import static libcore.icu.DateIntervalFormat.*;
+import android.icu.util.Calendar;
+import android.icu.util.TimeZone;
+import android.icu.util.ULocale;
+
+import static libcore.icu.DateIntervalFormat.formatDateRange;
+import static libcore.icu.DateUtilsBridge.*;
public class DateIntervalFormatTest extends junit.framework.TestCase {
private static final long MINUTE = 60 * 1000;
@@ -32,7 +34,7 @@ public class DateIntervalFormatTest extends junit.framework.TestCase {
public void test_formatDateInterval() throws Exception {
TimeZone tz = TimeZone.getTimeZone("America/Los_Angeles");
- Calendar c = Calendar.getInstance(tz, Locale.US);
+ Calendar c = Calendar.getInstance(tz, ULocale.US);
c.set(Calendar.MONTH, Calendar.JANUARY);
c.set(Calendar.DAY_OF_MONTH, 19);
c.set(Calendar.HOUR_OF_DAY, 3);
@@ -51,10 +53,10 @@ public class DateIntervalFormatTest extends junit.framework.TestCase {
long noonDuration = (8 * 60 + 30) * 60 * 1000 - 15 * 1000;
long midnightDuration = (3 * 60 + 30) * 60 * 1000 + 15 * 1000;
- Locale de_DE = new Locale("de", "DE");
- Locale en_US = new Locale("en", "US");
- Locale es_ES = new Locale("es", "ES");
- Locale es_US = new Locale("es", "US");
+ ULocale de_DE = new ULocale("de", "DE");
+ ULocale en_US = new ULocale("en", "US");
+ ULocale es_ES = new ULocale("es", "ES");
+ ULocale es_US = new ULocale("es", "US");
assertEquals("Monday", formatDateRange(en_US, tz, fixedTime, fixedTime + HOUR, FORMAT_SHOW_WEEKDAY));
assertEquals("January 19", formatDateRange(en_US, tz, timeWithCurrentYear, timeWithCurrentYear + HOUR, FORMAT_SHOW_DATE));
@@ -81,11 +83,11 @@ public class DateIntervalFormatTest extends junit.framework.TestCase {
assertEquals("1/19/2009 – 2/9/2012", formatDateRange(en_US, tz, fixedTime, fixedTime + 3 * YEAR, FORMAT_SHOW_YEAR | FORMAT_NUMERIC_DATE));
assertEquals("19.1.2009", formatDateRange(de_DE, tz, fixedTime, fixedTime + HOUR, FORMAT_SHOW_YEAR | FORMAT_NUMERIC_DATE));
- assertEquals("19.01.2009 - 22.01.2009", formatDateRange(de_DE, tz, fixedTime, fixedTime + 3 * DAY, FORMAT_SHOW_YEAR | FORMAT_NUMERIC_DATE));
- assertEquals("19.01.2009 - 22.04.2009", formatDateRange(de_DE, tz, fixedTime, fixedTime + 3 * MONTH, FORMAT_SHOW_YEAR | FORMAT_NUMERIC_DATE));
- assertEquals("19.01.2009 - 09.02.2012", formatDateRange(de_DE, tz, fixedTime, fixedTime + 3 * YEAR, FORMAT_SHOW_YEAR | FORMAT_NUMERIC_DATE));
+ assertEquals("19.01.2009 – 22.01.2009", formatDateRange(de_DE, tz, fixedTime, fixedTime + 3 * DAY, FORMAT_SHOW_YEAR | FORMAT_NUMERIC_DATE));
+ assertEquals("19.01.2009 – 22.04.2009", formatDateRange(de_DE, tz, fixedTime, fixedTime + 3 * MONTH, FORMAT_SHOW_YEAR | FORMAT_NUMERIC_DATE));
+ assertEquals("19.01.2009 – 09.02.2012", formatDateRange(de_DE, tz, fixedTime, fixedTime + 3 * YEAR, FORMAT_SHOW_YEAR | FORMAT_NUMERIC_DATE));
- assertEquals("1/19/2009", formatDateRange(es_US, tz, fixedTime, fixedTime + HOUR, FORMAT_SHOW_YEAR | FORMAT_NUMERIC_DATE));
+ assertEquals("19/1/2009", formatDateRange(es_US, tz, fixedTime, fixedTime + HOUR, FORMAT_SHOW_YEAR | FORMAT_NUMERIC_DATE));
assertEquals("19/1/2009–22/1/2009", formatDateRange(es_US, tz, fixedTime, fixedTime + 3 * DAY, FORMAT_SHOW_YEAR | FORMAT_NUMERIC_DATE));
assertEquals("19/1/2009–22/4/2009", formatDateRange(es_US, tz, fixedTime, fixedTime + 3 * MONTH, FORMAT_SHOW_YEAR | FORMAT_NUMERIC_DATE));
assertEquals("19/1/2009–9/2/2012", formatDateRange(es_US, tz, fixedTime, fixedTime + 3 * YEAR, FORMAT_SHOW_YEAR | FORMAT_NUMERIC_DATE));
@@ -114,60 +116,61 @@ public class DateIntervalFormatTest extends junit.framework.TestCase {
// The same tests but for de_DE.
- assertEquals("19.-22. Januar 2009", formatDateRange(de_DE, tz, fixedTime, fixedTime + 3 * DAY, 0));
- assertEquals("19.-22. Jan. 2009", formatDateRange(de_DE, tz, fixedTime, fixedTime + 3 * DAY, FORMAT_SHOW_DATE | FORMAT_ABBREV_ALL));
- assertEquals("Mo., 19. - Do., 22. Jan. 2009", formatDateRange(de_DE, tz, fixedTime, fixedTime + 3 * DAY, FORMAT_SHOW_WEEKDAY | FORMAT_ABBREV_ALL));
- assertEquals("Montag, 19. - Donnerstag, 22. Januar 2009", formatDateRange(de_DE, tz, fixedTime, fixedTime + 3 * DAY, FORMAT_SHOW_WEEKDAY));
+ assertEquals("19.–22. Januar 2009", formatDateRange(de_DE, tz, fixedTime, fixedTime + 3 * DAY, 0));
+ assertEquals("19.–22. Jan. 2009", formatDateRange(de_DE, tz, fixedTime, fixedTime + 3 * DAY, FORMAT_SHOW_DATE | FORMAT_ABBREV_ALL));
+ assertEquals("Mo., 19. – Do., 22. Jan. 2009", formatDateRange(de_DE, tz, fixedTime, fixedTime + 3 * DAY, FORMAT_SHOW_WEEKDAY | FORMAT_ABBREV_ALL));
+ assertEquals("Montag, 19. – Donnerstag, 22. Januar 2009", formatDateRange(de_DE, tz, fixedTime, fixedTime + 3 * DAY, FORMAT_SHOW_WEEKDAY));
- assertEquals("19. Januar - 22. April 2009", formatDateRange(de_DE, tz, fixedTime, fixedTime + 3 * MONTH, 0));
- assertEquals("19. Jan. - 22. Apr. 2009", formatDateRange(de_DE, tz, fixedTime, fixedTime + 3 * MONTH, FORMAT_SHOW_DATE | FORMAT_ABBREV_ALL));
- assertEquals("Mo., 19. Jan. - Mi., 22. Apr. 2009", formatDateRange(de_DE, tz, fixedTime, fixedTime + 3 * MONTH, FORMAT_SHOW_WEEKDAY | FORMAT_ABBREV_ALL));
- assertEquals("Januar-April 2009", formatDateRange(de_DE, tz, fixedTime, fixedTime + 3 * MONTH, FORMAT_NO_MONTH_DAY));
+ assertEquals("19. Januar – 22. April 2009", formatDateRange(de_DE, tz, fixedTime, fixedTime + 3 * MONTH, 0));
+ assertEquals("19. Jan. – 22. Apr. 2009", formatDateRange(de_DE, tz, fixedTime, fixedTime + 3 * MONTH, FORMAT_SHOW_DATE | FORMAT_ABBREV_ALL));
+ assertEquals("Mo., 19. Jan. – Mi., 22. Apr. 2009", formatDateRange(de_DE, tz, fixedTime, fixedTime + 3 * MONTH, FORMAT_SHOW_WEEKDAY | FORMAT_ABBREV_ALL));
+ assertEquals("Januar–April 2009", formatDateRange(de_DE, tz, fixedTime, fixedTime + 3 * MONTH, FORMAT_NO_MONTH_DAY));
- assertEquals("19. Jan. 2009 - 9. Feb. 2012", formatDateRange(de_DE, tz, fixedTime, fixedTime + 3 * YEAR, FORMAT_SHOW_DATE | FORMAT_ABBREV_ALL));
- assertEquals("Jan. 2009 - Feb. 2012", formatDateRange(de_DE, tz, fixedTime, fixedTime + 3 * YEAR, FORMAT_NO_MONTH_DAY | FORMAT_ABBREV_ALL));
- assertEquals("19. Januar 2009 - 9. Februar 2012", formatDateRange(de_DE, tz, fixedTime, fixedTime + 3 * YEAR, 0));
- assertEquals("Montag, 19. Januar 2009 - Donnerstag, 9. Februar 2012", formatDateRange(de_DE, tz, fixedTime, fixedTime + 3 * YEAR, FORMAT_SHOW_WEEKDAY));
+ assertEquals("19. Jan. 2009 – 9. Feb. 2012", formatDateRange(de_DE, tz, fixedTime, fixedTime + 3 * YEAR, FORMAT_SHOW_DATE | FORMAT_ABBREV_ALL));
+ assertEquals("Jan. 2009 – Feb. 2012", formatDateRange(de_DE, tz, fixedTime, fixedTime + 3 * YEAR, FORMAT_NO_MONTH_DAY | FORMAT_ABBREV_ALL));
+ assertEquals("19. Januar 2009 – 9. Februar 2012", formatDateRange(de_DE, tz, fixedTime, fixedTime + 3 * YEAR, 0));
+ assertEquals("Montag, 19. Januar 2009 – Donnerstag, 9. Februar 2012", formatDateRange(de_DE, tz, fixedTime, fixedTime + 3 * YEAR, FORMAT_SHOW_WEEKDAY));
// The same tests but for es_US.
- assertEquals("19–22 enero 2009", formatDateRange(es_US, tz, fixedTime, fixedTime + 3 * DAY, 0));
- assertEquals("19–22 ene. 2009", formatDateRange(es_US, tz, fixedTime, fixedTime + 3 * DAY, FORMAT_SHOW_DATE | FORMAT_ABBREV_ALL));
- assertEquals("lun., 19 ene.–jue., 22 ene. de 2009", formatDateRange(es_US, tz, fixedTime, fixedTime + 3 * DAY, FORMAT_SHOW_WEEKDAY | FORMAT_ABBREV_ALL));
- assertEquals("lunes, 19 enero–jueves, 22 enero de 2009", formatDateRange(es_US, tz, fixedTime, fixedTime + 3 * DAY, FORMAT_SHOW_WEEKDAY));
+ assertEquals("19–22 de enero de 2009", formatDateRange(es_US, tz, fixedTime, fixedTime + 3 * DAY, 0));
+ assertEquals("19 – 22 de ene. de 2009", formatDateRange(es_US, tz, fixedTime, fixedTime + 3 * DAY, FORMAT_SHOW_DATE | FORMAT_ABBREV_ALL));
+ assertEquals("lun., 19 de ene. – jue., 22 de ene. de 2009", formatDateRange(es_US, tz, fixedTime, fixedTime + 3 * DAY, FORMAT_SHOW_WEEKDAY | FORMAT_ABBREV_ALL));
+ assertEquals("lunes, 19 de enero–jueves, 22 de enero de 2009", formatDateRange(es_US, tz, fixedTime, fixedTime + 3 * DAY, FORMAT_SHOW_WEEKDAY));
- assertEquals("19 enero–22 abril de 2009", formatDateRange(es_US, tz, fixedTime, fixedTime + 3 * MONTH, 0));
- assertEquals("19 ene.–22 abr. de 2009", formatDateRange(es_US, tz, fixedTime, fixedTime + 3 * MONTH, FORMAT_SHOW_DATE | FORMAT_ABBREV_ALL));
- assertEquals("lun., 19 ene.–mié., 22 abr. de 2009", formatDateRange(es_US, tz, fixedTime, fixedTime + 3 * MONTH, FORMAT_SHOW_WEEKDAY | FORMAT_ABBREV_ALL));
+ assertEquals("19 de enero–22 de abril de 2009", formatDateRange(es_US, tz, fixedTime, fixedTime + 3 * MONTH, 0));
+ assertEquals("19 de ene. – 22 de abr. de 2009", formatDateRange(es_US, tz, fixedTime, fixedTime + 3 * MONTH, FORMAT_SHOW_DATE | FORMAT_ABBREV_ALL));
+ assertEquals("lun., 19 de ene. – mié., 22 de abr. de 2009", formatDateRange(es_US, tz, fixedTime, fixedTime + 3 * MONTH, FORMAT_SHOW_WEEKDAY | FORMAT_ABBREV_ALL));
assertEquals("enero–abril de 2009", formatDateRange(es_US, tz, fixedTime, fixedTime + 3 * MONTH, FORMAT_NO_MONTH_DAY));
- assertEquals("19 ene. de 2009–9 feb. de 2012", formatDateRange(es_US, tz, fixedTime, fixedTime + 3 * YEAR, FORMAT_SHOW_DATE | FORMAT_ABBREV_ALL));
- assertEquals("ene. 2009–feb. 2012", formatDateRange(es_US, tz, fixedTime, fixedTime + 3 * YEAR, FORMAT_NO_MONTH_DAY | FORMAT_ABBREV_ALL));
- assertEquals("19 enero de 2009–9 febrero de 2012", formatDateRange(es_US, tz, fixedTime, fixedTime + 3 * YEAR, 0));
- assertEquals("lunes, 19 enero de 2009–jueves, 9 febrero de 2012", formatDateRange(es_US, tz, fixedTime, fixedTime + 3 * YEAR, FORMAT_SHOW_WEEKDAY));
+ assertEquals("19 de ene. de 2009 – 9 de feb. de 2012", formatDateRange(es_US, tz, fixedTime, fixedTime + 3 * YEAR, FORMAT_SHOW_DATE | FORMAT_ABBREV_ALL));
+ assertEquals("ene. de 2009 – feb. de 2012", formatDateRange(es_US, tz, fixedTime, fixedTime + 3 * YEAR, FORMAT_NO_MONTH_DAY | FORMAT_ABBREV_ALL));
+
+ assertEquals("19 de enero de 2009–9 de febrero de 2012", formatDateRange(es_US, tz, fixedTime, fixedTime + 3 * YEAR, 0));
+ assertEquals("lunes, 19 de enero de 2009–jueves, 9 de febrero de 2012", formatDateRange(es_US, tz, fixedTime, fixedTime + 3 * YEAR, FORMAT_SHOW_WEEKDAY));
// The same tests but for es_ES.
- assertEquals("19–22 enero 2009", formatDateRange(es_ES, tz, fixedTime, fixedTime + 3 * DAY, 0));
+ assertEquals("19–22 de enero de 2009", formatDateRange(es_ES, tz, fixedTime, fixedTime + 3 * DAY, 0));
assertEquals("19–22 ene. 2009", formatDateRange(es_ES, tz, fixedTime, fixedTime + 3 * DAY, FORMAT_SHOW_DATE | FORMAT_ABBREV_ALL));
- assertEquals("lun., 19 ene.–jue., 22 ene. de 2009", formatDateRange(es_ES, tz, fixedTime, fixedTime + 3 * DAY, FORMAT_SHOW_WEEKDAY | FORMAT_ABBREV_ALL));
- assertEquals("lunes, 19 enero–jueves, 22 enero de 2009", formatDateRange(es_ES, tz, fixedTime, fixedTime + 3 * DAY, FORMAT_SHOW_WEEKDAY));
+ assertEquals("lun., 19 ene.–jue., 22 ene. 2009", formatDateRange(es_ES, tz, fixedTime, fixedTime + 3 * DAY, FORMAT_SHOW_WEEKDAY | FORMAT_ABBREV_ALL));
+ assertEquals("lunes, 19 de enero–jueves, 22 de enero de 2009", formatDateRange(es_ES, tz, fixedTime, fixedTime + 3 * DAY, FORMAT_SHOW_WEEKDAY));
- assertEquals("19 enero–22 abril de 2009", formatDateRange(es_ES, tz, fixedTime, fixedTime + 3 * MONTH, 0));
- assertEquals("19 ene.–22 abr. de 2009", formatDateRange(es_ES, tz, fixedTime, fixedTime + 3 * MONTH, FORMAT_SHOW_DATE | FORMAT_ABBREV_ALL));
- assertEquals("lun., 19 ene.–mié., 22 abr. de 2009", formatDateRange(es_ES, tz, fixedTime, fixedTime + 3 * MONTH, FORMAT_SHOW_WEEKDAY | FORMAT_ABBREV_ALL));
+ assertEquals("19 de enero–22 de abril de 2009", formatDateRange(es_ES, tz, fixedTime, fixedTime + 3 * MONTH, 0));
+ assertEquals("19 ene.–22 abr. 2009", formatDateRange(es_ES, tz, fixedTime, fixedTime + 3 * MONTH, FORMAT_SHOW_DATE | FORMAT_ABBREV_ALL));
+ assertEquals("lun., 19 ene.–mié., 22 abr. 2009", formatDateRange(es_ES, tz, fixedTime, fixedTime + 3 * MONTH, FORMAT_SHOW_WEEKDAY | FORMAT_ABBREV_ALL));
assertEquals("enero–abril de 2009", formatDateRange(es_ES, tz, fixedTime, fixedTime + 3 * MONTH, FORMAT_NO_MONTH_DAY));
- assertEquals("19 ene. de 2009–9 feb. de 2012", formatDateRange(es_ES, tz, fixedTime, fixedTime + 3 * YEAR, FORMAT_SHOW_DATE | FORMAT_ABBREV_ALL));
+ assertEquals("19 ene. 2009–9 feb. 2012", formatDateRange(es_ES, tz, fixedTime, fixedTime + 3 * YEAR, FORMAT_SHOW_DATE | FORMAT_ABBREV_ALL));
assertEquals("ene. 2009–feb. 2012", formatDateRange(es_ES, tz, fixedTime, fixedTime + 3 * YEAR, FORMAT_NO_MONTH_DAY | FORMAT_ABBREV_ALL));
- assertEquals("19 enero de 2009–9 febrero de 2012", formatDateRange(es_ES, tz, fixedTime, fixedTime + 3 * YEAR, 0));
- assertEquals("lunes, 19 enero de 2009–jueves, 9 febrero de 2012", formatDateRange(es_ES, tz, fixedTime, fixedTime + 3 * YEAR, FORMAT_SHOW_WEEKDAY));
+ assertEquals("19 de enero de 2009–9 de febrero de 2012", formatDateRange(es_ES, tz, fixedTime, fixedTime + 3 * YEAR, 0));
+ assertEquals("lunes, 19 de enero de 2009–jueves, 9 de febrero de 2012", formatDateRange(es_ES, tz, fixedTime, fixedTime + 3 * YEAR, FORMAT_SHOW_WEEKDAY));
}
// http://b/8862241 - we should be able to format dates past 2038.
// See also http://code.google.com/p/android/issues/detail?id=13050.
public void test8862241() throws Exception {
- Locale l = Locale.US;
+ ULocale l = ULocale.US;
TimeZone tz = TimeZone.getTimeZone("America/Los_Angeles");
Calendar c = Calendar.getInstance(tz, l);
c.clear();
@@ -181,7 +184,7 @@ public class DateIntervalFormatTest extends junit.framework.TestCase {
// http://b/10089890 - we should take the given time zone into account.
public void test10089890() throws Exception {
- Locale l = Locale.US;
+ ULocale l = ULocale.US;
TimeZone utc = TimeZone.getTimeZone("UTC");
TimeZone pacific = TimeZone.getTimeZone("America/Los_Angeles");
int flags = FORMAT_SHOW_DATE | FORMAT_ABBREV_ALL | FORMAT_SHOW_TIME | FORMAT_24HOUR;
@@ -203,7 +206,7 @@ public class DateIntervalFormatTest extends junit.framework.TestCase {
int abbr12 = time12 | FORMAT_ABBREV_ALL;
int abbr24 = time24 | FORMAT_ABBREV_ALL;
- Locale l = Locale.US;
+ ULocale l = ULocale.US;
TimeZone utc = TimeZone.getTimeZone("UTC");
// Full length on-the-hour times.
@@ -230,7 +233,7 @@ public class DateIntervalFormatTest extends junit.framework.TestCase {
// http://b/10560853 - when the time is not displayed, an end time 0 ms into the next day is
// considered to belong to the previous day.
public void test10560853_when_time_not_displayed() throws Exception {
- Locale l = Locale.US;
+ ULocale l = ULocale.US;
TimeZone utc = TimeZone.getTimeZone("UTC");
long midnight = 0;
@@ -254,7 +257,7 @@ public class DateIntervalFormatTest extends junit.framework.TestCase {
// http://b/10560853 - when the start and end times are otherwise on the same day,
// an end time 0 ms into the next day is considered to belong to the previous day.
public void test10560853_for_single_day_events() throws Exception {
- Locale l = Locale.US;
+ ULocale l = ULocale.US;
TimeZone utc = TimeZone.getTimeZone("UTC");
int flags = FORMAT_SHOW_TIME | FORMAT_24HOUR | FORMAT_SHOW_DATE;
@@ -266,7 +269,7 @@ public class DateIntervalFormatTest extends junit.framework.TestCase {
// The fix for http://b/10560853 didn't work except for the day around the epoch, which was
// all the unit test checked!
public void test_single_day_events_later_than_epoch() throws Exception {
- Locale l = Locale.US;
+ ULocale l = ULocale.US;
TimeZone utc = TimeZone.getTimeZone("UTC");
int flags = FORMAT_SHOW_TIME | FORMAT_24HOUR | FORMAT_SHOW_DATE;
@@ -284,7 +287,7 @@ public class DateIntervalFormatTest extends junit.framework.TestCase {
// The fix for http://b/10560853 didn't work except for UTC, which was
// all the unit test checked!
public void test_single_day_events_not_in_UTC() throws Exception {
- Locale l = Locale.US;
+ ULocale l = ULocale.US;
TimeZone pacific = TimeZone.getTimeZone("America/Los_Angeles");
int flags = FORMAT_SHOW_TIME | FORMAT_24HOUR | FORMAT_SHOW_DATE;
@@ -305,7 +308,7 @@ public class DateIntervalFormatTest extends junit.framework.TestCase {
// http://b/10209343 - even if the caller didn't explicitly ask us to include the year,
// we should do so for years other than the current year.
public void test10209343_when_not_this_year() {
- Locale l = Locale.US;
+ ULocale l = ULocale.US;
TimeZone utc = TimeZone.getTimeZone("UTC");
int flags = FORMAT_SHOW_DATE | FORMAT_SHOW_WEEKDAY | FORMAT_SHOW_TIME | FORMAT_24HOUR;
@@ -328,7 +331,7 @@ public class DateIntervalFormatTest extends junit.framework.TestCase {
// http://b/10209343 - for the current year, we should honor the FORMAT_SHOW_YEAR flags.
public void test10209343_when_this_year() {
// Construct a date in the current year (whenever the test happens to be run).
- Locale l = Locale.US;
+ ULocale l = ULocale.US;
TimeZone utc = TimeZone.getTimeZone("UTC");
Calendar c = Calendar.getInstance(utc, l);
c.set(Calendar.MONTH, Calendar.FEBRUARY);
@@ -363,7 +366,7 @@ public class DateIntervalFormatTest extends junit.framework.TestCase {
// http://b/8467515 - yet another y2k38 bug report.
public void test8467515() throws Exception {
- Locale l = Locale.US;
+ ULocale l = ULocale.US;
TimeZone utc = TimeZone.getTimeZone("UTC");
int flags = FORMAT_SHOW_DATE | FORMAT_SHOW_WEEKDAY | FORMAT_SHOW_YEAR | FORMAT_ABBREV_MONTH | FORMAT_ABBREV_WEEKDAY;
long t;
@@ -383,7 +386,7 @@ public class DateIntervalFormatTest extends junit.framework.TestCase {
// http://b/12004664
public void test12004664() throws Exception {
TimeZone utc = TimeZone.getTimeZone("UTC");
- Calendar c = Calendar.getInstance(utc, Locale.US);
+ Calendar c = Calendar.getInstance(utc, ULocale.US);
c.clear();
c.set(Calendar.YEAR, 1980);
c.set(Calendar.MONTH, Calendar.FEBRUARY);
@@ -392,26 +395,26 @@ public class DateIntervalFormatTest extends junit.framework.TestCase {
long thisYear = c.getTimeInMillis();
int flags = FORMAT_SHOW_DATE | FORMAT_SHOW_WEEKDAY | FORMAT_SHOW_YEAR;
- assertEquals("Sunday, February 10, 1980", formatDateRange(new Locale("en", "US"), utc, thisYear, thisYear, flags));
+ assertEquals("Sunday, February 10, 1980", formatDateRange(new ULocale("en", "US"), utc, thisYear, thisYear, flags));
- // If we supported non-Gregorian calendars, this is what that we'd expect for these locales.
+ // If we supported non-Gregorian calendars, this is what that we'd expect for these ULocales.
// This is really the correct behavior, but since java.util.Calendar currently only supports
// the Gregorian calendar, we want to deliberately force icu4c to agree, otherwise we'd have
// a mix of calendars throughout an app's UI depending on whether Java or native code formatted
// the date.
- // assertEquals("یکشنبه ۲۱ بهمن ۱۳۵۸ ه‍.ش.", formatDateRange(new Locale("fa"), utc, thisYear, thisYear, flags));
- // assertEquals("AP ۱۳۵۸ سلواغه ۲۱, یکشنبه", formatDateRange(new Locale("ps"), utc, thisYear, thisYear, flags));
- // assertEquals("วันอาทิตย์ 10 กุมภาพันธ์ 2523", formatDateRange(new Locale("th"), utc, thisYear, thisYear, flags));
+ // assertEquals("یکشنبه ۲۱ بهمن ۱۳۵۸ ه‍.ش.", formatDateRange(new ULocale("fa"), utc, thisYear, thisYear, flags));
+ // assertEquals("AP ۱۳۵۸ سلواغه ۲۱, یکشنبه", formatDateRange(new ULocale("ps"), utc, thisYear, thisYear, flags));
+ // assertEquals("วันอาทิตย์ 10 กุมภาพันธ์ 2523", formatDateRange(new ULocale("th"), utc, thisYear, thisYear, flags));
// For now, here are the localized Gregorian strings instead...
- assertEquals("یکشنبه ۱۰ فوریهٔ ۱۹۸۰", formatDateRange(new Locale("fa"), utc, thisYear, thisYear, flags));
- assertEquals("یکشنبه د ۱۹۸۰ د فبروري ۱۰", formatDateRange(new Locale("ps"), utc, thisYear, thisYear, flags));
- assertEquals("วันอาทิตย์ 10 กุมภาพันธ์ 1980", formatDateRange(new Locale("th"), utc, thisYear, thisYear, flags));
+ assertEquals("یکشنبه ۱۰ فوریهٔ ۱۹۸۰", formatDateRange(new ULocale("fa"), utc, thisYear, thisYear, flags));
+ assertEquals("یکشنبه د ۱۹۸۰ د فبروري ۱۰", formatDateRange(new ULocale("ps"), utc, thisYear, thisYear, flags));
+ assertEquals("วันอาทิตย์ที่ 10 กุมภาพันธ์ ค.ศ. 1980", formatDateRange(new ULocale("th"), utc, thisYear, thisYear, flags));
}
// http://b/13234532
public void test13234532() throws Exception {
- Locale l = Locale.US;
+ ULocale l = ULocale.US;
TimeZone utc = TimeZone.getTimeZone("UTC");
int flags = FORMAT_SHOW_TIME | FORMAT_ABBREV_ALL | FORMAT_12HOUR;
@@ -420,4 +423,13 @@ public class DateIntervalFormatTest extends junit.framework.TestCase {
assertEquals("11 AM – 1 PM", formatDateRange(l, utc, 11*HOUR, 13*HOUR, flags));
assertEquals("2 – 3 PM", formatDateRange(l, utc, 14*HOUR, 15*HOUR, flags));
}
+
+ // http://b/20708022
+ public void testEndOfDayOnLastDayOfMonth() throws Exception {
+ final ULocale locale = new ULocale("en");
+ final TimeZone timeZone = TimeZone.getTimeZone("UTC");
+
+ assertEquals("11:00 PM – 12:00 AM", formatDateRange(locale, timeZone,
+ 1430434800000L, 1430438400000L, FORMAT_SHOW_TIME));
+ }
}
diff --git a/luni/src/test/java/libcore/icu/ICUTest.java b/luni/src/test/java/libcore/icu/ICUTest.java
index a7cc7a0..5eab070 100644
--- a/luni/src/test/java/libcore/icu/ICUTest.java
+++ b/luni/src/test/java/libcore/icu/ICUTest.java
@@ -20,6 +20,7 @@ import java.text.BreakIterator;
import java.text.Collator;
import java.util.Arrays;
import java.util.Locale;
+import libcore.util.ZoneInfoDB;
public class ICUTest extends junit.framework.TestCase {
public void test_getISOLanguages() throws Exception {
@@ -152,24 +153,24 @@ public class ICUTest extends junit.framework.TestCase {
assertEquals("sr_ME_#Latn", sr_Latn_ME.toString());
assertEquals("Latn", sr_Latn_ME.getScript());
- assertEquals("Српски", sr_Cyrl_BA.getDisplayLanguage(sr_Cyrl_BA));
+ assertEquals("српски", sr_Cyrl_BA.getDisplayLanguage(sr_Cyrl_BA));
assertEquals("Босна и Херцеговина", sr_Cyrl_BA.getDisplayCountry(sr_Cyrl_BA));
- assertEquals("Ћирилица", sr_Cyrl_BA.getDisplayScript(sr_Cyrl_BA));
+ assertEquals("ћирилица", sr_Cyrl_BA.getDisplayScript(sr_Cyrl_BA));
assertEquals("", sr_Cyrl_BA.getDisplayVariant(sr_Cyrl_BA));
- assertEquals("Српски", sr_Cyrl_ME.getDisplayLanguage(sr_Cyrl_ME));
+ assertEquals("српски", sr_Cyrl_ME.getDisplayLanguage(sr_Cyrl_ME));
assertEquals("Црна Гора", sr_Cyrl_ME.getDisplayCountry(sr_Cyrl_ME));
- assertEquals("Ћирилица", sr_Cyrl_ME.getDisplayScript(sr_Cyrl_ME));
+ assertEquals("ћирилица", sr_Cyrl_ME.getDisplayScript(sr_Cyrl_ME));
assertEquals("", sr_Cyrl_ME.getDisplayVariant(sr_Cyrl_ME));
- assertEquals("Srpski", sr_Latn_BA.getDisplayLanguage(sr_Latn_BA));
+ assertEquals("srpski", sr_Latn_BA.getDisplayLanguage(sr_Latn_BA));
assertEquals("Bosna i Hercegovina", sr_Latn_BA.getDisplayCountry(sr_Latn_BA));
- assertEquals("Latinica", sr_Latn_BA.getDisplayScript(sr_Latn_BA));
+ assertEquals("latinica", sr_Latn_BA.getDisplayScript(sr_Latn_BA));
assertEquals("", sr_Latn_BA.getDisplayVariant(sr_Latn_BA));
- assertEquals("Srpski", sr_Latn_ME.getDisplayLanguage(sr_Latn_ME));
+ assertEquals("srpski", sr_Latn_ME.getDisplayLanguage(sr_Latn_ME));
assertEquals("Crna Gora", sr_Latn_ME.getDisplayCountry(sr_Latn_ME));
- assertEquals("Latinica", sr_Latn_ME.getDisplayScript(sr_Latn_ME));
+ assertEquals("latinica", sr_Latn_ME.getDisplayScript(sr_Latn_ME));
assertEquals("", sr_Latn_ME.getDisplayVariant(sr_Latn_ME));
assertEquals("BIH", sr_Cyrl_BA.getISO3Country());
@@ -253,4 +254,14 @@ public class ICUTest extends junit.framework.TestCase {
ICU.setDefaultLocale(initialDefaultLocale);
}
}
+
+ /** Confirms that ICU agrees with the rest of libcore about the version of the TZ data in use. */
+ public void testTimeZoneDataVersion() {
+ String icu4cTzVersion = ICU.getTZDataVersion();
+ String zoneInfoTzVersion = ZoneInfoDB.getInstance().getVersion();
+ assertEquals(icu4cTzVersion, zoneInfoTzVersion);
+
+ String icu4jTzVersion = android.icu.util.TimeZone.getTZDataVersion();
+ assertEquals(icu4jTzVersion, zoneInfoTzVersion);
+ }
}
diff --git a/luni/src/test/java/libcore/icu/LocaleDataTest.java b/luni/src/test/java/libcore/icu/LocaleDataTest.java
index 0a83c53..09c3f0f 100644
--- a/luni/src/test/java/libcore/icu/LocaleDataTest.java
+++ b/luni/src/test/java/libcore/icu/LocaleDataTest.java
@@ -24,7 +24,7 @@ public class LocaleDataTest extends junit.framework.TestCase {
for (Locale l : Locale.getAvailableLocales()) {
LocaleData d = LocaleData.get(l);
// System.err.format("%20s %s %s %s\n", l, d.yesterday, d.today, d.tomorrow);
- // System.err.format("%20s %10s %10s\n", l, d.timeFormat12, d.timeFormat24);
+ // System.err.format("%20s %10s %10s\n", l, d.timeFormat_hm, d.timeFormat_Hm);
}
}
@@ -73,7 +73,7 @@ public class LocaleDataTest extends junit.framework.TestCase {
assertEquals("leden", l.longStandAloneMonthNames[0]);
assertEquals("led", l.shortStandAloneMonthNames[0]);
- assertEquals("l", l.tinyStandAloneMonthNames[0]);
+ assertEquals("1", l.tinyStandAloneMonthNames[0]);
}
public void test_ko_KR() throws Exception {
@@ -124,11 +124,11 @@ public class LocaleDataTest extends junit.framework.TestCase {
// http://b/7924970
public void testTimeFormat12And24() throws Exception {
LocaleData en_US = LocaleData.get(Locale.US);
- assertEquals("h:mm a", en_US.timeFormat12);
- assertEquals("HH:mm", en_US.timeFormat24);
+ assertEquals("h:mm a", en_US.timeFormat_hm);
+ assertEquals("HH:mm", en_US.timeFormat_Hm);
LocaleData ja_JP = LocaleData.get(Locale.JAPAN);
- assertEquals("aK:mm", ja_JP.timeFormat12);
- assertEquals("H:mm", ja_JP.timeFormat24);
+ assertEquals("aK:mm", ja_JP.timeFormat_hm);
+ assertEquals("H:mm", ja_JP.timeFormat_Hm);
}
}
diff --git a/luni/src/test/java/libcore/icu/RelativeDateTimeFormatterTest.java b/luni/src/test/java/libcore/icu/RelativeDateTimeFormatterTest.java
new file mode 100644
index 0000000..101896f
--- /dev/null
+++ b/luni/src/test/java/libcore/icu/RelativeDateTimeFormatterTest.java
@@ -0,0 +1,667 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package libcore.icu;
+
+import android.icu.util.ULocale;
+
+import java.util.Calendar;
+import java.util.Locale;
+import java.util.TimeZone;
+
+import static libcore.icu.DateUtilsBridge.FORMAT_ABBREV_ALL;
+import static libcore.icu.DateUtilsBridge.FORMAT_ABBREV_RELATIVE;
+import static libcore.icu.DateUtilsBridge.FORMAT_NO_YEAR;
+import static libcore.icu.DateUtilsBridge.FORMAT_NUMERIC_DATE;
+import static libcore.icu.DateUtilsBridge.FORMAT_SHOW_YEAR;
+import static libcore.icu.RelativeDateTimeFormatter.DAY_IN_MILLIS;
+import static libcore.icu.RelativeDateTimeFormatter.HOUR_IN_MILLIS;
+import static libcore.icu.RelativeDateTimeFormatter.MINUTE_IN_MILLIS;
+import static libcore.icu.RelativeDateTimeFormatter.SECOND_IN_MILLIS;
+import static libcore.icu.RelativeDateTimeFormatter.WEEK_IN_MILLIS;
+import static libcore.icu.RelativeDateTimeFormatter.YEAR_IN_MILLIS;
+import static libcore.icu.RelativeDateTimeFormatter.getRelativeDateTimeString;
+import static libcore.icu.RelativeDateTimeFormatter.getRelativeTimeSpanString;
+
+public class RelativeDateTimeFormatterTest extends junit.framework.TestCase {
+
+ // Tests adopted from CTS tests for DateUtils.getRelativeTimeSpanString.
+ public void test_getRelativeTimeSpanStringCTS() throws Exception {
+ Locale en_US = new Locale("en", "US");
+ TimeZone tz = TimeZone.getTimeZone("GMT");
+ Calendar cal = Calendar.getInstance(tz, en_US);
+ // Feb 5, 2015 at 10:50 GMT
+ cal.set(2015, Calendar.FEBRUARY, 5, 10, 50, 0);
+ final long baseTime = cal.getTimeInMillis();
+
+ assertEquals("0 minutes ago",
+ getRelativeTimeSpanString(en_US, tz, baseTime - SECOND_IN_MILLIS, baseTime,
+ MINUTE_IN_MILLIS, 0));
+ assertEquals("In 0 minutes",
+ getRelativeTimeSpanString(en_US, tz, baseTime + SECOND_IN_MILLIS, baseTime,
+ MINUTE_IN_MILLIS, 0));
+
+ assertEquals("1 minute ago",
+ getRelativeTimeSpanString(en_US, tz, 0, MINUTE_IN_MILLIS, MINUTE_IN_MILLIS, 0));
+ assertEquals("In 1 minute",
+ getRelativeTimeSpanString(en_US, tz, MINUTE_IN_MILLIS, 0, MINUTE_IN_MILLIS, 0));
+
+ assertEquals("42 minutes ago",
+ getRelativeTimeSpanString(en_US, tz, baseTime - 42 * MINUTE_IN_MILLIS, baseTime,
+ MINUTE_IN_MILLIS, 0));
+ assertEquals("In 42 minutes",
+ getRelativeTimeSpanString(en_US, tz, baseTime + 42 * MINUTE_IN_MILLIS, baseTime,
+ MINUTE_IN_MILLIS, 0));
+
+ final long TWO_HOURS_IN_MS = 2 * HOUR_IN_MILLIS;
+ assertEquals("2 hours ago",
+ getRelativeTimeSpanString(en_US, tz, baseTime - TWO_HOURS_IN_MS, baseTime,
+ MINUTE_IN_MILLIS, FORMAT_NUMERIC_DATE));
+ assertEquals("In 2 hours",
+ getRelativeTimeSpanString(en_US, tz, baseTime + TWO_HOURS_IN_MS, baseTime,
+ MINUTE_IN_MILLIS, FORMAT_NUMERIC_DATE));
+
+ assertEquals("In 42 min.",
+ getRelativeTimeSpanString(en_US, tz, baseTime + (42 * MINUTE_IN_MILLIS), baseTime,
+ MINUTE_IN_MILLIS, FORMAT_ABBREV_RELATIVE));
+
+ assertEquals("Tomorrow",
+ getRelativeTimeSpanString(en_US, tz, DAY_IN_MILLIS, 0, DAY_IN_MILLIS, 0));
+ assertEquals("In 2 days",
+ getRelativeTimeSpanString(en_US, tz, 2 * DAY_IN_MILLIS, 0, DAY_IN_MILLIS, 0));
+ assertEquals("Yesterday",
+ getRelativeTimeSpanString(en_US, tz, 0, DAY_IN_MILLIS, DAY_IN_MILLIS, 0));
+ assertEquals("2 days ago",
+ getRelativeTimeSpanString(en_US, tz, 0, 2 * DAY_IN_MILLIS, DAY_IN_MILLIS, 0));
+
+ final long DAY_DURATION = 5 * 24 * 60 * 60 * 1000;
+ assertEquals("5 days ago",
+ getRelativeTimeSpanString(en_US, tz, baseTime - DAY_DURATION, baseTime,
+ DAY_IN_MILLIS, 0));
+ }
+
+ private void test_getRelativeTimeSpanString_helper(long delta, long minResolution, int flags,
+ String expectedInPast,
+ String expectedInFuture) throws Exception {
+ Locale en_US = new Locale("en", "US");
+ TimeZone tz = TimeZone.getTimeZone("America/Los_Angeles");
+ Calendar cal = Calendar.getInstance(tz, en_US);
+ // Feb 5, 2015 at 10:50 PST
+ cal.set(2015, Calendar.FEBRUARY, 5, 10, 50, 0);
+ final long base = cal.getTimeInMillis();
+
+ assertEquals(expectedInPast,
+ getRelativeTimeSpanString(en_US, tz, base - delta, base, minResolution, flags));
+ assertEquals(expectedInFuture,
+ getRelativeTimeSpanString(en_US, tz, base + delta, base, minResolution, flags));
+ }
+
+ private void test_getRelativeTimeSpanString_helper(long delta, long minResolution,
+ String expectedInPast,
+ String expectedInFuture) throws Exception {
+ test_getRelativeTimeSpanString_helper(delta, minResolution, 0, expectedInPast, expectedInFuture);
+ }
+
+ public void test_getRelativeTimeSpanString() throws Exception {
+
+ test_getRelativeTimeSpanString_helper(0 * SECOND_IN_MILLIS, 0, "0 seconds ago", "0 seconds ago");
+ test_getRelativeTimeSpanString_helper(1 * MINUTE_IN_MILLIS, 0, "1 minute ago", "In 1 minute");
+ test_getRelativeTimeSpanString_helper(1 * MINUTE_IN_MILLIS, 0, "1 minute ago", "In 1 minute");
+ test_getRelativeTimeSpanString_helper(5 * DAY_IN_MILLIS, 0, "5 days ago", "In 5 days");
+
+ test_getRelativeTimeSpanString_helper(0 * SECOND_IN_MILLIS, SECOND_IN_MILLIS, "0 seconds ago",
+ "0 seconds ago");
+ test_getRelativeTimeSpanString_helper(1 * SECOND_IN_MILLIS, SECOND_IN_MILLIS, "1 second ago",
+ "In 1 second");
+ test_getRelativeTimeSpanString_helper(2 * SECOND_IN_MILLIS, SECOND_IN_MILLIS, "2 seconds ago",
+ "In 2 seconds");
+ test_getRelativeTimeSpanString_helper(25 * SECOND_IN_MILLIS, SECOND_IN_MILLIS, "25 seconds ago",
+ "In 25 seconds");
+ test_getRelativeTimeSpanString_helper(75 * SECOND_IN_MILLIS, SECOND_IN_MILLIS, "1 minute ago",
+ "In 1 minute");
+ test_getRelativeTimeSpanString_helper(5000 * SECOND_IN_MILLIS, SECOND_IN_MILLIS, "1 hour ago",
+ "In 1 hour");
+
+ test_getRelativeTimeSpanString_helper(0 * MINUTE_IN_MILLIS, MINUTE_IN_MILLIS, "0 minutes ago",
+ "0 minutes ago");
+ test_getRelativeTimeSpanString_helper(1 * MINUTE_IN_MILLIS, MINUTE_IN_MILLIS, "1 minute ago",
+ "In 1 minute");
+ test_getRelativeTimeSpanString_helper(2 * MINUTE_IN_MILLIS, MINUTE_IN_MILLIS, "2 minutes ago",
+ "In 2 minutes");
+ test_getRelativeTimeSpanString_helper(25 * MINUTE_IN_MILLIS, MINUTE_IN_MILLIS, "25 minutes ago",
+ "In 25 minutes");
+ test_getRelativeTimeSpanString_helper(75 * MINUTE_IN_MILLIS, MINUTE_IN_MILLIS, "1 hour ago",
+ "In 1 hour");
+ test_getRelativeTimeSpanString_helper(720 * MINUTE_IN_MILLIS, MINUTE_IN_MILLIS, "12 hours ago",
+ "In 12 hours");
+
+ test_getRelativeTimeSpanString_helper(0 * HOUR_IN_MILLIS, HOUR_IN_MILLIS, "0 hours ago",
+ "0 hours ago");
+ test_getRelativeTimeSpanString_helper(1 * HOUR_IN_MILLIS, HOUR_IN_MILLIS, "1 hour ago",
+ "In 1 hour");
+ test_getRelativeTimeSpanString_helper(2 * HOUR_IN_MILLIS, HOUR_IN_MILLIS, "2 hours ago",
+ "In 2 hours");
+ test_getRelativeTimeSpanString_helper(5 * HOUR_IN_MILLIS, HOUR_IN_MILLIS, "5 hours ago",
+ "In 5 hours");
+ test_getRelativeTimeSpanString_helper(20 * HOUR_IN_MILLIS, HOUR_IN_MILLIS, "20 hours ago",
+ "In 20 hours");
+
+ test_getRelativeTimeSpanString_helper(0 * DAY_IN_MILLIS, DAY_IN_MILLIS, "Today", "Today");
+ test_getRelativeTimeSpanString_helper(20 * HOUR_IN_MILLIS, DAY_IN_MILLIS, "Yesterday",
+ "Tomorrow");
+ test_getRelativeTimeSpanString_helper(24 * HOUR_IN_MILLIS, DAY_IN_MILLIS, "Yesterday",
+ "Tomorrow");
+ test_getRelativeTimeSpanString_helper(2 * DAY_IN_MILLIS, DAY_IN_MILLIS, "2 days ago",
+ "In 2 days");
+ test_getRelativeTimeSpanString_helper(25 * DAY_IN_MILLIS, DAY_IN_MILLIS, "January 11",
+ "March 2");
+
+ test_getRelativeTimeSpanString_helper(0 * WEEK_IN_MILLIS, WEEK_IN_MILLIS, "0 weeks ago",
+ "0 weeks ago");
+ test_getRelativeTimeSpanString_helper(1 * WEEK_IN_MILLIS, WEEK_IN_MILLIS, "1 week ago",
+ "In 1 week");
+ test_getRelativeTimeSpanString_helper(2 * WEEK_IN_MILLIS, WEEK_IN_MILLIS, "2 weeks ago",
+ "In 2 weeks");
+ test_getRelativeTimeSpanString_helper(25 * WEEK_IN_MILLIS, WEEK_IN_MILLIS, "25 weeks ago",
+ "In 25 weeks");
+
+ // duration >= minResolution
+ test_getRelativeTimeSpanString_helper(30 * SECOND_IN_MILLIS, 0, "30 seconds ago",
+ "In 30 seconds");
+ test_getRelativeTimeSpanString_helper(30 * MINUTE_IN_MILLIS, MINUTE_IN_MILLIS,
+ "30 minutes ago", "In 30 minutes");
+ test_getRelativeTimeSpanString_helper(30 * HOUR_IN_MILLIS, MINUTE_IN_MILLIS, "Yesterday",
+ "Tomorrow");
+ test_getRelativeTimeSpanString_helper(5 * DAY_IN_MILLIS, MINUTE_IN_MILLIS, "5 days ago",
+ "In 5 days");
+ test_getRelativeTimeSpanString_helper(30 * WEEK_IN_MILLIS, MINUTE_IN_MILLIS, "July 10, 2014",
+ "September 3");
+ test_getRelativeTimeSpanString_helper(5 * 365 * DAY_IN_MILLIS, MINUTE_IN_MILLIS,
+ "February 6, 2010", "February 4, 2020");
+
+ test_getRelativeTimeSpanString_helper(60 * SECOND_IN_MILLIS, MINUTE_IN_MILLIS, "1 minute ago",
+ "In 1 minute");
+ test_getRelativeTimeSpanString_helper(120 * SECOND_IN_MILLIS - 1, MINUTE_IN_MILLIS,
+ "1 minute ago", "In 1 minute");
+ test_getRelativeTimeSpanString_helper(60 * MINUTE_IN_MILLIS, HOUR_IN_MILLIS, "1 hour ago",
+ "In 1 hour");
+ test_getRelativeTimeSpanString_helper(120 * MINUTE_IN_MILLIS - 1, HOUR_IN_MILLIS, "1 hour ago",
+ "In 1 hour");
+ test_getRelativeTimeSpanString_helper(2 * HOUR_IN_MILLIS, DAY_IN_MILLIS, "Today", "Today");
+ test_getRelativeTimeSpanString_helper(12 * HOUR_IN_MILLIS, DAY_IN_MILLIS, "Yesterday",
+ "Today");
+ test_getRelativeTimeSpanString_helper(24 * HOUR_IN_MILLIS, DAY_IN_MILLIS, "Yesterday",
+ "Tomorrow");
+ test_getRelativeTimeSpanString_helper(48 * HOUR_IN_MILLIS, DAY_IN_MILLIS, "2 days ago",
+ "In 2 days");
+ test_getRelativeTimeSpanString_helper(45 * HOUR_IN_MILLIS, DAY_IN_MILLIS, "2 days ago",
+ "In 2 days");
+ test_getRelativeTimeSpanString_helper(7 * DAY_IN_MILLIS, WEEK_IN_MILLIS, "1 week ago",
+ "In 1 week");
+ test_getRelativeTimeSpanString_helper(14 * DAY_IN_MILLIS - 1, WEEK_IN_MILLIS, "1 week ago",
+ "In 1 week");
+
+ // duration < minResolution
+ test_getRelativeTimeSpanString_helper(59 * SECOND_IN_MILLIS, MINUTE_IN_MILLIS, "0 minutes ago",
+ "In 0 minutes");
+ test_getRelativeTimeSpanString_helper(59 * MINUTE_IN_MILLIS, HOUR_IN_MILLIS, "0 hours ago",
+ "In 0 hours");
+ test_getRelativeTimeSpanString_helper(HOUR_IN_MILLIS - 1, HOUR_IN_MILLIS, "0 hours ago",
+ "In 0 hours");
+ test_getRelativeTimeSpanString_helper(DAY_IN_MILLIS - 1, DAY_IN_MILLIS, "Yesterday",
+ "Tomorrow");
+ test_getRelativeTimeSpanString_helper(20 * SECOND_IN_MILLIS, WEEK_IN_MILLIS, "0 weeks ago",
+ "In 0 weeks");
+ test_getRelativeTimeSpanString_helper(WEEK_IN_MILLIS - 1, WEEK_IN_MILLIS, "0 weeks ago",
+ "In 0 weeks");
+ }
+
+ public void test_getRelativeTimeSpanStringAbbrev() throws Exception {
+ int flags = FORMAT_ABBREV_RELATIVE;
+
+ test_getRelativeTimeSpanString_helper(0 * SECOND_IN_MILLIS, 0, flags, "0 sec. ago",
+ "0 sec. ago");
+ test_getRelativeTimeSpanString_helper(1 * MINUTE_IN_MILLIS, 0, flags, "1 min. ago",
+ "In 1 min.");
+ test_getRelativeTimeSpanString_helper(5 * DAY_IN_MILLIS, 0, flags, "5 days ago", "In 5 days");
+
+ test_getRelativeTimeSpanString_helper(0 * SECOND_IN_MILLIS, SECOND_IN_MILLIS, flags,
+ "0 sec. ago", "0 sec. ago");
+ test_getRelativeTimeSpanString_helper(1 * SECOND_IN_MILLIS, SECOND_IN_MILLIS, flags,
+ "1 sec. ago", "In 1 sec.");
+ test_getRelativeTimeSpanString_helper(2 * SECOND_IN_MILLIS, SECOND_IN_MILLIS, flags,
+ "2 sec. ago", "In 2 sec.");
+ test_getRelativeTimeSpanString_helper(25 * SECOND_IN_MILLIS, SECOND_IN_MILLIS, flags,
+ "25 sec. ago", "In 25 sec.");
+ test_getRelativeTimeSpanString_helper(75 * SECOND_IN_MILLIS, SECOND_IN_MILLIS, flags,
+ "1 min. ago", "In 1 min.");
+ test_getRelativeTimeSpanString_helper(5000 * SECOND_IN_MILLIS, SECOND_IN_MILLIS, flags,
+ "1 hr. ago", "In 1 hr.");
+
+ test_getRelativeTimeSpanString_helper(0 * MINUTE_IN_MILLIS, MINUTE_IN_MILLIS, flags,
+ "0 min. ago", "0 min. ago");
+ test_getRelativeTimeSpanString_helper(1 * MINUTE_IN_MILLIS, MINUTE_IN_MILLIS, flags,
+ "1 min. ago", "In 1 min.");
+ test_getRelativeTimeSpanString_helper(2 * MINUTE_IN_MILLIS, MINUTE_IN_MILLIS, flags,
+ "2 min. ago", "In 2 min.");
+ test_getRelativeTimeSpanString_helper(25 * MINUTE_IN_MILLIS, MINUTE_IN_MILLIS, flags,
+ "25 min. ago", "In 25 min.");
+ test_getRelativeTimeSpanString_helper(75 * MINUTE_IN_MILLIS, MINUTE_IN_MILLIS, flags,
+ "1 hr. ago", "In 1 hr.");
+ test_getRelativeTimeSpanString_helper(720 * MINUTE_IN_MILLIS, MINUTE_IN_MILLIS, flags,
+ "12 hr. ago", "In 12 hr.");
+
+ test_getRelativeTimeSpanString_helper(0 * HOUR_IN_MILLIS, HOUR_IN_MILLIS, flags,
+ "0 hr. ago", "0 hr. ago");
+ test_getRelativeTimeSpanString_helper(1 * HOUR_IN_MILLIS, HOUR_IN_MILLIS, flags,
+ "1 hr. ago", "In 1 hr.");
+ test_getRelativeTimeSpanString_helper(2 * HOUR_IN_MILLIS, HOUR_IN_MILLIS, flags,
+ "2 hr. ago", "In 2 hr.");
+ test_getRelativeTimeSpanString_helper(5 * HOUR_IN_MILLIS, HOUR_IN_MILLIS, flags,
+ "5 hr. ago", "In 5 hr.");
+ test_getRelativeTimeSpanString_helper(20 * HOUR_IN_MILLIS, HOUR_IN_MILLIS, flags,
+ "20 hr. ago", "In 20 hr.");
+
+ test_getRelativeTimeSpanString_helper(0 * DAY_IN_MILLIS, DAY_IN_MILLIS, flags, "Today",
+ "Today");
+ test_getRelativeTimeSpanString_helper(20 * HOUR_IN_MILLIS, DAY_IN_MILLIS, flags,
+ "Yesterday", "Tomorrow");
+ test_getRelativeTimeSpanString_helper(24 * HOUR_IN_MILLIS, DAY_IN_MILLIS, flags,
+ "Yesterday", "Tomorrow");
+ test_getRelativeTimeSpanString_helper(2 * DAY_IN_MILLIS, DAY_IN_MILLIS, flags,
+ "2 days ago", "In 2 days");
+ test_getRelativeTimeSpanString_helper(25 * DAY_IN_MILLIS, DAY_IN_MILLIS, flags,
+ "January 11", "March 2");
+
+ test_getRelativeTimeSpanString_helper(0 * WEEK_IN_MILLIS, WEEK_IN_MILLIS, flags,
+ "0 wk. ago", "0 wk. ago");
+ test_getRelativeTimeSpanString_helper(1 * WEEK_IN_MILLIS, WEEK_IN_MILLIS, flags,
+ "1 wk. ago", "In 1 wk.");
+ test_getRelativeTimeSpanString_helper(2 * WEEK_IN_MILLIS, WEEK_IN_MILLIS, flags,
+ "2 wk. ago", "In 2 wk.");
+ test_getRelativeTimeSpanString_helper(25 * WEEK_IN_MILLIS, WEEK_IN_MILLIS, flags,
+ "25 wk. ago", "In 25 wk.");
+
+ // duration >= minResolution
+ test_getRelativeTimeSpanString_helper(30 * SECOND_IN_MILLIS, 0, flags, "30 sec. ago",
+ "In 30 sec.");
+ test_getRelativeTimeSpanString_helper(30 * MINUTE_IN_MILLIS, MINUTE_IN_MILLIS, flags,
+ "30 min. ago", "In 30 min.");
+ test_getRelativeTimeSpanString_helper(30 * HOUR_IN_MILLIS, MINUTE_IN_MILLIS, flags,
+ "Yesterday", "Tomorrow");
+ test_getRelativeTimeSpanString_helper(5 * DAY_IN_MILLIS, MINUTE_IN_MILLIS, flags,
+ "5 days ago", "In 5 days");
+ test_getRelativeTimeSpanString_helper(30 * WEEK_IN_MILLIS, MINUTE_IN_MILLIS, flags,
+ "July 10, 2014", "September 3");
+ test_getRelativeTimeSpanString_helper(5 * 365 * DAY_IN_MILLIS, MINUTE_IN_MILLIS, flags,
+ "February 6, 2010", "February 4, 2020");
+
+ test_getRelativeTimeSpanString_helper(60 * SECOND_IN_MILLIS, MINUTE_IN_MILLIS, flags,
+ "1 min. ago", "In 1 min.");
+ test_getRelativeTimeSpanString_helper(120 * SECOND_IN_MILLIS - 1, MINUTE_IN_MILLIS, flags,
+ "1 min. ago", "In 1 min.");
+ test_getRelativeTimeSpanString_helper(60 * MINUTE_IN_MILLIS, HOUR_IN_MILLIS, flags,
+ "1 hr. ago", "In 1 hr.");
+ test_getRelativeTimeSpanString_helper(120 * MINUTE_IN_MILLIS - 1, HOUR_IN_MILLIS, flags,
+ "1 hr. ago", "In 1 hr.");
+ test_getRelativeTimeSpanString_helper(2 * HOUR_IN_MILLIS, DAY_IN_MILLIS, flags, "Today",
+ "Today");
+ test_getRelativeTimeSpanString_helper(12 * HOUR_IN_MILLIS, DAY_IN_MILLIS, flags,
+ "Yesterday", "Today");
+ test_getRelativeTimeSpanString_helper(24 * HOUR_IN_MILLIS, DAY_IN_MILLIS, flags,
+ "Yesterday", "Tomorrow");
+ test_getRelativeTimeSpanString_helper(48 * HOUR_IN_MILLIS, DAY_IN_MILLIS, flags,
+ "2 days ago", "In 2 days");
+ test_getRelativeTimeSpanString_helper(45 * HOUR_IN_MILLIS, DAY_IN_MILLIS, flags,
+ "2 days ago", "In 2 days");
+ test_getRelativeTimeSpanString_helper(7 * DAY_IN_MILLIS, WEEK_IN_MILLIS, flags,
+ "1 wk. ago", "In 1 wk.");
+ test_getRelativeTimeSpanString_helper(14 * DAY_IN_MILLIS - 1, WEEK_IN_MILLIS, flags,
+ "1 wk. ago", "In 1 wk.");
+
+ // duration < minResolution
+ test_getRelativeTimeSpanString_helper(59 * SECOND_IN_MILLIS, MINUTE_IN_MILLIS, flags,
+ "0 min. ago", "In 0 min.");
+ test_getRelativeTimeSpanString_helper(59 * MINUTE_IN_MILLIS, HOUR_IN_MILLIS, flags,
+ "0 hr. ago", "In 0 hr.");
+ test_getRelativeTimeSpanString_helper(HOUR_IN_MILLIS - 1, HOUR_IN_MILLIS, flags,
+ "0 hr. ago", "In 0 hr.");
+ test_getRelativeTimeSpanString_helper(DAY_IN_MILLIS - 1, DAY_IN_MILLIS, flags,
+ "Yesterday", "Tomorrow");
+ test_getRelativeTimeSpanString_helper(20 * SECOND_IN_MILLIS, WEEK_IN_MILLIS, flags,
+ "0 wk. ago", "In 0 wk.");
+ test_getRelativeTimeSpanString_helper(WEEK_IN_MILLIS - 1, WEEK_IN_MILLIS, flags,
+ "0 wk. ago", "In 0 wk.");
+
+ }
+
+ public void test_getRelativeTimeSpanStringGerman() throws Exception {
+ // Bug: 19744876
+ // We need to specify the timezone and the time explicitly. Otherwise it
+ // may not always give a correct answer of "tomorrow" by using
+ // (now + DAY_IN_MILLIS).
+ Locale de_DE = new Locale("de", "DE");
+ TimeZone tz = TimeZone.getTimeZone("Europe/Berlin");
+ Calendar cal = Calendar.getInstance(tz, de_DE);
+ // Feb 5, 2015 at 10:50 CET
+ cal.set(2015, Calendar.FEBRUARY, 5, 10, 50, 0);
+ final long now = cal.getTimeInMillis();
+
+ // 42 minutes ago
+ assertEquals("Vor 42 Minuten", getRelativeTimeSpanString(de_DE, tz,
+ now - 42 * MINUTE_IN_MILLIS, now, MINUTE_IN_MILLIS, 0));
+ // In 42 minutes
+ assertEquals("In 42 Minuten", getRelativeTimeSpanString(de_DE, tz,
+ now + 42 * MINUTE_IN_MILLIS, now, MINUTE_IN_MILLIS, 0));
+ // Yesterday
+ assertEquals("Gestern", getRelativeTimeSpanString(de_DE, tz,
+ now - DAY_IN_MILLIS, now, DAY_IN_MILLIS, 0));
+ // The day before yesterday
+ assertEquals("Vorgestern", getRelativeTimeSpanString(de_DE, tz,
+ now - 2 * DAY_IN_MILLIS, now, DAY_IN_MILLIS, 0));
+ // Tomorrow
+ assertEquals("Morgen", getRelativeTimeSpanString(de_DE, tz,
+ now + DAY_IN_MILLIS, now, DAY_IN_MILLIS, 0));
+ // The day after tomorrow
+ assertEquals("Übermorgen", getRelativeTimeSpanString(de_DE, tz,
+ now + 2 * DAY_IN_MILLIS, now, DAY_IN_MILLIS, 0));
+ }
+
+ public void test_getRelativeTimeSpanStringFrench() throws Exception {
+ Locale fr_FR = new Locale("fr", "FR");
+ TimeZone tz = TimeZone.getTimeZone("Europe/Paris");
+ Calendar cal = Calendar.getInstance(tz, fr_FR);
+ // Feb 5, 2015 at 10:50 CET
+ cal.set(2015, Calendar.FEBRUARY, 5, 10, 50, 0);
+ final long now = cal.getTimeInMillis();
+
+ // 42 minutes ago
+ assertEquals("Il y a 42 minutes", getRelativeTimeSpanString(fr_FR, tz,
+ now - (42 * MINUTE_IN_MILLIS), now, MINUTE_IN_MILLIS, 0));
+ // In 42 minutes
+ assertEquals("Dans 42 minutes", getRelativeTimeSpanString(fr_FR, tz,
+ now + (42 * MINUTE_IN_MILLIS), now, MINUTE_IN_MILLIS, 0));
+ // Yesterday
+ assertEquals("Hier", getRelativeTimeSpanString(fr_FR, tz,
+ now - DAY_IN_MILLIS, now, DAY_IN_MILLIS, 0));
+ // The day before yesterday
+ assertEquals("Avant-hier", getRelativeTimeSpanString(fr_FR, tz,
+ now - 2 * DAY_IN_MILLIS, now, DAY_IN_MILLIS, 0));
+ // Tomorrow
+ assertEquals("Demain", getRelativeTimeSpanString(fr_FR, tz,
+ now + DAY_IN_MILLIS, now, DAY_IN_MILLIS, 0));
+ // The day after tomorrow
+ assertEquals("Après-demain", getRelativeTimeSpanString(fr_FR, tz,
+ now + 2 * DAY_IN_MILLIS, now, DAY_IN_MILLIS, 0));
+ }
+
+ // Tests adopted from CTS tests for DateUtils.getRelativeDateTimeString.
+ public void test_getRelativeDateTimeStringCTS() throws Exception {
+ Locale en_US = Locale.getDefault();
+ TimeZone tz = TimeZone.getDefault();
+ final long baseTime = System.currentTimeMillis();
+
+ final long DAY_DURATION = 5 * 24 * 60 * 60 * 1000;
+ assertNotNull(getRelativeDateTimeString(en_US, tz, baseTime - DAY_DURATION, baseTime,
+ MINUTE_IN_MILLIS, DAY_IN_MILLIS,
+ FORMAT_NUMERIC_DATE));
+ }
+
+ public void test_getRelativeDateTimeString() throws Exception {
+ Locale en_US = new Locale("en", "US");
+ TimeZone tz = TimeZone.getTimeZone("America/Los_Angeles");
+ Calendar cal = Calendar.getInstance(tz, en_US);
+ // Feb 5, 2015 at 10:50 PST
+ cal.set(2015, Calendar.FEBRUARY, 5, 10, 50, 0);
+ final long base = cal.getTimeInMillis();
+
+ assertEquals("5 seconds ago, 10:49 AM",
+ getRelativeDateTimeString(en_US, tz, base - 5 * SECOND_IN_MILLIS, base, 0,
+ MINUTE_IN_MILLIS, 0));
+ assertEquals("5 min. ago, 10:45 AM",
+ getRelativeDateTimeString(en_US, tz, base - 5 * MINUTE_IN_MILLIS, base, 0,
+ HOUR_IN_MILLIS, FORMAT_ABBREV_RELATIVE));
+ assertEquals("0 hr. ago, 10:45 AM",
+ getRelativeDateTimeString(en_US, tz, base - 5 * MINUTE_IN_MILLIS, base,
+ HOUR_IN_MILLIS, DAY_IN_MILLIS, FORMAT_ABBREV_RELATIVE));
+ assertEquals("5 hours ago, 5:50 AM",
+ getRelativeDateTimeString(en_US, tz, base - 5 * HOUR_IN_MILLIS, base,
+ HOUR_IN_MILLIS, DAY_IN_MILLIS, 0));
+ assertEquals("Yesterday, 7:50 PM",
+ getRelativeDateTimeString(en_US, tz, base - 15 * HOUR_IN_MILLIS, base, 0,
+ WEEK_IN_MILLIS, FORMAT_ABBREV_RELATIVE));
+ assertEquals("5 days ago, 10:50 AM",
+ getRelativeDateTimeString(en_US, tz, base - 5 * DAY_IN_MILLIS, base, 0,
+ WEEK_IN_MILLIS, 0));
+ assertEquals("Jan 29, 10:50 AM",
+ getRelativeDateTimeString(en_US, tz, base - 7 * DAY_IN_MILLIS, base, 0,
+ WEEK_IN_MILLIS, 0));
+ assertEquals("11/27/2014, 10:50 AM",
+ getRelativeDateTimeString(en_US, tz, base - 10 * WEEK_IN_MILLIS, base, 0,
+ WEEK_IN_MILLIS, 0));
+ assertEquals("11/27/2014, 10:50 AM",
+ getRelativeDateTimeString(en_US, tz, base - 10 * WEEK_IN_MILLIS, base, 0,
+ YEAR_IN_MILLIS, 0));
+
+ // User-supplied flags should be ignored when formatting the date clause.
+ final int FORMAT_SHOW_WEEKDAY = 0x00002;
+ assertEquals("11/27/2014, 10:50 AM",
+ getRelativeDateTimeString(en_US, tz, base - 10 * WEEK_IN_MILLIS, base, 0,
+ WEEK_IN_MILLIS,
+ FORMAT_ABBREV_ALL | FORMAT_SHOW_WEEKDAY));
+ }
+
+ public void test_getRelativeDateTimeStringDST() throws Exception {
+ Locale en_US = new Locale("en", "US");
+ TimeZone tz = TimeZone.getTimeZone("America/Los_Angeles");
+ Calendar cal = Calendar.getInstance(tz, en_US);
+
+ // DST starts on Mar 9, 2014 at 2:00 AM.
+ // So 5 hours before 3:15 AM should be formatted as 'Yesterday, 9:15 PM'.
+ cal.set(2014, Calendar.MARCH, 9, 3, 15, 0);
+ long base = cal.getTimeInMillis();
+ assertEquals("Yesterday, 9:15 PM",
+ getRelativeDateTimeString(en_US, tz, base - 5 * HOUR_IN_MILLIS, base, 0,
+ WEEK_IN_MILLIS, 0));
+
+ // 1 hour after 2:00 AM should be formatted as 'In 1 hour, 4:00 AM'.
+ cal.set(2014, Calendar.MARCH, 9, 2, 0, 0);
+ base = cal.getTimeInMillis();
+ assertEquals("In 1 hour, 4:00 AM",
+ getRelativeDateTimeString(en_US, tz, base + 1 * HOUR_IN_MILLIS, base, 0,
+ WEEK_IN_MILLIS, 0));
+
+ // DST ends on Nov 2, 2014 at 2:00 AM. Clocks are turned backward 1 hour to
+ // 1:00 AM. 8 hours before 5:20 AM should be 'Yesterday, 10:20 PM'.
+ cal.set(2014, Calendar.NOVEMBER, 2, 5, 20, 0);
+ base = cal.getTimeInMillis();
+ assertEquals("Yesterday, 10:20 PM",
+ getRelativeDateTimeString(en_US, tz, base - 8 * HOUR_IN_MILLIS, base, 0,
+ WEEK_IN_MILLIS, 0));
+
+ cal.set(2014, Calendar.NOVEMBER, 2, 0, 45, 0);
+ base = cal.getTimeInMillis();
+ // 45 minutes after 0:45 AM should be 'In 45 minutes, 1:30 AM'.
+ assertEquals("In 45 minutes, 1:30 AM",
+ getRelativeDateTimeString(en_US, tz, base + 45 * MINUTE_IN_MILLIS, base, 0,
+ WEEK_IN_MILLIS, 0));
+ // 45 minutes later, it should be 'In 45 minutes, 1:15 AM'.
+ assertEquals("In 45 minutes, 1:15 AM",
+ getRelativeDateTimeString(en_US, tz, base + 90 * MINUTE_IN_MILLIS,
+ base + 45 * MINUTE_IN_MILLIS, 0, WEEK_IN_MILLIS, 0));
+ // Another 45 minutes later, it should be 'In 45 minutes, 2:00 AM'.
+ assertEquals("In 45 minutes, 2:00 AM",
+ getRelativeDateTimeString(en_US, tz, base + 135 * MINUTE_IN_MILLIS,
+ base + 90 * MINUTE_IN_MILLIS, 0, WEEK_IN_MILLIS, 0));
+ }
+
+
+ public void test_getRelativeDateTimeStringItalian() throws Exception {
+ Locale it_IT = new Locale("it", "IT");
+ TimeZone tz = TimeZone.getTimeZone("Europe/Rome");
+ Calendar cal = Calendar.getInstance(tz, it_IT);
+ // 05 febbraio 2015 20:15
+ cal.set(2015, Calendar.FEBRUARY, 5, 20, 15, 0);
+ final long base = cal.getTimeInMillis();
+
+ assertEquals("5 secondi fa, 20:14",
+ getRelativeDateTimeString(it_IT, tz, base - 5 * SECOND_IN_MILLIS, base, 0,
+ MINUTE_IN_MILLIS, 0));
+ assertEquals("5 min. fa, 20:10",
+ getRelativeDateTimeString(it_IT, tz, base - 5 * MINUTE_IN_MILLIS, base, 0,
+ HOUR_IN_MILLIS, FORMAT_ABBREV_RELATIVE));
+ assertEquals("0 h. fa, 20:10",
+ getRelativeDateTimeString(it_IT, tz, base - 5 * MINUTE_IN_MILLIS, base,
+ HOUR_IN_MILLIS, DAY_IN_MILLIS, FORMAT_ABBREV_RELATIVE));
+ assertEquals("Ieri, 22:15",
+ getRelativeDateTimeString(it_IT, tz, base - 22 * HOUR_IN_MILLIS, base, 0,
+ WEEK_IN_MILLIS, FORMAT_ABBREV_RELATIVE));
+ assertEquals("5 giorni fa, 20:15",
+ getRelativeDateTimeString(it_IT, tz, base - 5 * DAY_IN_MILLIS, base, 0,
+ WEEK_IN_MILLIS, 0));
+ assertEquals("27/11/2014, 20:15",
+ getRelativeDateTimeString(it_IT, tz, base - 10 * WEEK_IN_MILLIS, base, 0,
+ WEEK_IN_MILLIS, 0));
+ }
+
+ // http://b/5252772: detect the actual date difference
+ public void test5252772() throws Exception {
+ Locale en_US = new Locale("en", "US");
+ TimeZone tz = TimeZone.getTimeZone("America/Los_Angeles");
+
+ // Now is Sep 2, 2011, 10:23 AM PDT.
+ Calendar nowCalendar = Calendar.getInstance(tz, en_US);
+ nowCalendar.set(2011, Calendar.SEPTEMBER, 2, 10, 23, 0);
+ final long now = nowCalendar.getTimeInMillis();
+
+ // Sep 1, 2011, 10:24 AM
+ Calendar yesterdayCalendar1 = Calendar.getInstance(tz, en_US);
+ yesterdayCalendar1.set(2011, Calendar.SEPTEMBER, 1, 10, 24, 0);
+ long yesterday1 = yesterdayCalendar1.getTimeInMillis();
+ assertEquals("Yesterday, 10:24 AM",
+ getRelativeDateTimeString(en_US, tz, yesterday1, now, MINUTE_IN_MILLIS,
+ WEEK_IN_MILLIS, 0));
+
+ // Sep 1, 2011, 10:22 AM
+ Calendar yesterdayCalendar2 = Calendar.getInstance(tz, en_US);
+ yesterdayCalendar2.set(2011, Calendar.SEPTEMBER, 1, 10, 22, 0);
+ long yesterday2 = yesterdayCalendar2.getTimeInMillis();
+ assertEquals("Yesterday, 10:22 AM",
+ getRelativeDateTimeString(en_US, tz, yesterday2, now, MINUTE_IN_MILLIS,
+ WEEK_IN_MILLIS, 0));
+
+ // Aug 31, 2011, 10:24 AM
+ Calendar twoDaysAgoCalendar1 = Calendar.getInstance(tz, en_US);
+ twoDaysAgoCalendar1.set(2011, Calendar.AUGUST, 31, 10, 24, 0);
+ long twoDaysAgo1 = twoDaysAgoCalendar1.getTimeInMillis();
+ assertEquals("2 days ago, 10:24 AM",
+ getRelativeDateTimeString(en_US, tz, twoDaysAgo1, now, MINUTE_IN_MILLIS,
+ WEEK_IN_MILLIS, 0));
+
+ // Aug 31, 2011, 10:22 AM
+ Calendar twoDaysAgoCalendar2 = Calendar.getInstance(tz, en_US);
+ twoDaysAgoCalendar2.set(2011, Calendar.AUGUST, 31, 10, 22, 0);
+ long twoDaysAgo2 = twoDaysAgoCalendar2.getTimeInMillis();
+ assertEquals("2 days ago, 10:22 AM",
+ getRelativeDateTimeString(en_US, tz, twoDaysAgo2, now, MINUTE_IN_MILLIS,
+ WEEK_IN_MILLIS, 0));
+
+ // Sep 3, 2011, 10:22 AM
+ Calendar tomorrowCalendar1 = Calendar.getInstance(tz, en_US);
+ tomorrowCalendar1.set(2011, Calendar.SEPTEMBER, 3, 10, 22, 0);
+ long tomorrow1 = tomorrowCalendar1.getTimeInMillis();
+ assertEquals("Tomorrow, 10:22 AM",
+ getRelativeDateTimeString(en_US, tz, tomorrow1, now, MINUTE_IN_MILLIS,
+ WEEK_IN_MILLIS, 0));
+
+ // Sep 3, 2011, 10:24 AM
+ Calendar tomorrowCalendar2 = Calendar.getInstance(tz, en_US);
+ tomorrowCalendar2.set(2011, Calendar.SEPTEMBER, 3, 10, 24, 0);
+ long tomorrow2 = tomorrowCalendar2.getTimeInMillis();
+ assertEquals("Tomorrow, 10:24 AM",
+ getRelativeDateTimeString(en_US, tz, tomorrow2, now, MINUTE_IN_MILLIS,
+ WEEK_IN_MILLIS, 0));
+
+ // Sep 4, 2011, 10:22 AM
+ Calendar twoDaysLaterCalendar1 = Calendar.getInstance(tz, en_US);
+ twoDaysLaterCalendar1.set(2011, Calendar.SEPTEMBER, 4, 10, 22, 0);
+ long twoDaysLater1 = twoDaysLaterCalendar1.getTimeInMillis();
+ assertEquals("In 2 days, 10:22 AM",
+ getRelativeDateTimeString(en_US, tz, twoDaysLater1, now, MINUTE_IN_MILLIS,
+ WEEK_IN_MILLIS, 0));
+
+ // Sep 4, 2011, 10:24 AM
+ Calendar twoDaysLaterCalendar2 = Calendar.getInstance(tz, en_US);
+ twoDaysLaterCalendar2.set(2011, Calendar.SEPTEMBER, 4, 10, 24, 0);
+ long twoDaysLater2 = twoDaysLaterCalendar2.getTimeInMillis();
+ assertEquals("In 2 days, 10:24 AM",
+ getRelativeDateTimeString(en_US, tz, twoDaysLater2, now, MINUTE_IN_MILLIS,
+ WEEK_IN_MILLIS, 0));
+ }
+
+ // b/19822016: show / hide the year based on the dates in the arguments.
+ public void test_bug19822016() throws Exception {
+ Locale en_US = new Locale("en", "US");
+ TimeZone tz = TimeZone.getTimeZone("America/Los_Angeles");
+ Calendar cal = Calendar.getInstance(tz, en_US);
+ // Feb 5, 2012 at 10:50 PST
+ cal.set(2012, Calendar.FEBRUARY, 5, 10, 50, 0);
+ long base = cal.getTimeInMillis();
+
+ assertEquals("Feb 5, 5:50 AM", getRelativeDateTimeString(en_US, tz,
+ base - 5 * HOUR_IN_MILLIS, base, 0, MINUTE_IN_MILLIS, 0));
+ assertEquals("Jan 29, 10:50 AM", getRelativeDateTimeString(en_US, tz,
+ base - 7 * DAY_IN_MILLIS, base, 0, WEEK_IN_MILLIS, 0));
+ assertEquals("11/27/2011, 10:50 AM", getRelativeDateTimeString(en_US, tz,
+ base - 10 * WEEK_IN_MILLIS, base, 0, WEEK_IN_MILLIS, 0));
+
+ assertEquals("January 6", getRelativeTimeSpanString(en_US, tz,
+ base - 30 * DAY_IN_MILLIS, base, DAY_IN_MILLIS, 0));
+ assertEquals("January 6", getRelativeTimeSpanString(en_US, tz,
+ base - 30 * DAY_IN_MILLIS, base, DAY_IN_MILLIS, FORMAT_NO_YEAR));
+ assertEquals("January 6, 2012", getRelativeTimeSpanString(en_US, tz,
+ base - 30 * DAY_IN_MILLIS, base, DAY_IN_MILLIS, FORMAT_SHOW_YEAR));
+ assertEquals("December 7, 2011", getRelativeTimeSpanString(en_US, tz,
+ base - 60 * DAY_IN_MILLIS, base, DAY_IN_MILLIS, 0));
+ assertEquals("December 7, 2011", getRelativeTimeSpanString(en_US, tz,
+ base - 60 * DAY_IN_MILLIS, base, DAY_IN_MILLIS, FORMAT_SHOW_YEAR));
+ assertEquals("December 7", getRelativeTimeSpanString(en_US, tz,
+ base - 60 * DAY_IN_MILLIS, base, DAY_IN_MILLIS, FORMAT_NO_YEAR));
+
+ // Feb 5, 2018 at 10:50 PST
+ cal.set(2018, Calendar.FEBRUARY, 5, 10, 50, 0);
+ base = cal.getTimeInMillis();
+ assertEquals("Feb 5, 5:50 AM", getRelativeDateTimeString(en_US, tz,
+ base - 5 * HOUR_IN_MILLIS, base, 0, MINUTE_IN_MILLIS, 0));
+ assertEquals("Jan 29, 10:50 AM", getRelativeDateTimeString(en_US, tz,
+ base - 7 * DAY_IN_MILLIS, base, 0, WEEK_IN_MILLIS, 0));
+ assertEquals("11/27/2017, 10:50 AM", getRelativeDateTimeString(en_US, tz,
+ base - 10 * WEEK_IN_MILLIS, base, 0, WEEK_IN_MILLIS, 0));
+
+ assertEquals("January 6", getRelativeTimeSpanString(en_US, tz,
+ base - 30 * DAY_IN_MILLIS, base, DAY_IN_MILLIS, 0));
+ assertEquals("January 6", getRelativeTimeSpanString(en_US, tz,
+ base - 30 * DAY_IN_MILLIS, base, DAY_IN_MILLIS, FORMAT_NO_YEAR));
+ assertEquals("January 6, 2018", getRelativeTimeSpanString(en_US, tz,
+ base - 30 * DAY_IN_MILLIS, base, DAY_IN_MILLIS, FORMAT_SHOW_YEAR));
+ assertEquals("December 7, 2017", getRelativeTimeSpanString(en_US, tz,
+ base - 60 * DAY_IN_MILLIS, base, DAY_IN_MILLIS, 0));
+ assertEquals("December 7, 2017", getRelativeTimeSpanString(en_US, tz,
+ base - 60 * DAY_IN_MILLIS, base, DAY_IN_MILLIS, FORMAT_SHOW_YEAR));
+ assertEquals("December 7", getRelativeTimeSpanString(en_US, tz,
+ base - 60 * DAY_IN_MILLIS, base, DAY_IN_MILLIS, FORMAT_NO_YEAR));
+ }
+}
diff --git a/luni/src/test/java/libcore/io/OsTest.java b/luni/src/test/java/libcore/io/OsTest.java
index a0d1e5a..9b38ee9 100644
--- a/luni/src/test/java/libcore/io/OsTest.java
+++ b/luni/src/test/java/libcore/io/OsTest.java
@@ -16,18 +16,27 @@
package libcore.io;
+import android.system.ErrnoException;
+import android.system.NetlinkSocketAddress;
+import android.system.OsConstants;
+import android.system.PacketSocketAddress;
+import android.system.StructTimeval;
import android.system.StructUcred;
import java.io.File;
import java.io.FileDescriptor;
import java.io.FileInputStream;
import java.io.FileOutputStream;
+import java.net.Inet4Address;
+import java.net.Inet6Address;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.InetUnixAddress;
+import java.net.NetworkInterface;
import java.net.ServerSocket;
import java.net.SocketAddress;
import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets;
+import java.util.Arrays;
import java.util.Locale;
import junit.framework.TestCase;
import static android.system.OsConstants.*;
@@ -44,6 +53,20 @@ public class OsTest extends TestCase {
s.close();
}
+ public void testFcntlInt() throws Exception {
+ File f = File.createTempFile("OsTest", "tst");
+ FileInputStream fis = null;
+ try {
+ fis = new FileInputStream(f);
+ Libcore.os.fcntlInt(fis.getFD(), F_SETFD, FD_CLOEXEC);
+ int flags = Libcore.os.fcntlVoid(fis.getFD(), F_GETFD);
+ assertTrue((flags & FD_CLOEXEC) != 0);
+ } finally {
+ IoUtils.closeQuietly(fis);
+ f.delete();
+ }
+ }
+
public void testUnixDomainSockets_in_file_system() throws Exception {
String path = System.getProperty("java.io.tmpdir") + "/test_unix_socket";
new File(path).delete();
@@ -196,9 +219,10 @@ public class OsTest extends TestCase {
fis.close();
}
- public void test_byteBufferPositions_sendto_recvfrom() throws Exception {
- final FileDescriptor serverFd = Libcore.os.socket(AF_INET6, SOCK_STREAM, 0);
- Libcore.os.bind(serverFd, InetAddress.getLoopbackAddress(), 0);
+ static void checkByteBufferPositions_sendto_recvfrom(
+ int family, InetAddress loopback) throws Exception {
+ final FileDescriptor serverFd = Libcore.os.socket(family, SOCK_STREAM, 0);
+ Libcore.os.bind(serverFd, loopback, 0);
Libcore.os.listen(serverFd, 5);
InetSocketAddress address = (InetSocketAddress) Libcore.os.getsockname(serverFd);
@@ -232,7 +256,7 @@ public class OsTest extends TestCase {
server.start();
- FileDescriptor clientFd = Libcore.os.socket(AF_INET6, SOCK_STREAM, 0);
+ FileDescriptor clientFd = Libcore.os.socket(family, SOCK_STREAM, 0);
Libcore.os.connect(clientFd, address.getAddress(), address.getPort());
final byte[] bytes = "good bye, cruel black hole with fancy distortion".getBytes(StandardCharsets.US_ASCII);
@@ -254,4 +278,201 @@ public class OsTest extends TestCase {
Libcore.os.close(clientFd);
}
+
+ public void test_NetlinkSocket() throws Exception {
+ FileDescriptor nlSocket = Libcore.os.socket(AF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE);
+ Libcore.os.bind(nlSocket, new NetlinkSocketAddress());
+ NetlinkSocketAddress address = (NetlinkSocketAddress) Libcore.os.getsockname(nlSocket);
+ assertTrue(address.getPortId() > 0);
+ assertEquals(0, address.getGroupsMask());
+
+ NetlinkSocketAddress nlKernel = new NetlinkSocketAddress();
+ Libcore.os.connect(nlSocket, nlKernel);
+ NetlinkSocketAddress nlPeer = (NetlinkSocketAddress) Libcore.os.getpeername(nlSocket);
+ assertEquals(0, nlPeer.getPortId());
+ assertEquals(0, nlPeer.getGroupsMask());
+ Libcore.os.close(nlSocket);
+ }
+
+ public void test_PacketSocketAddress() throws Exception {
+ NetworkInterface lo = NetworkInterface.getByName("lo");
+ FileDescriptor fd = Libcore.os.socket(AF_PACKET, SOCK_DGRAM, ETH_P_IPV6);
+ PacketSocketAddress addr = new PacketSocketAddress((short) ETH_P_IPV6, lo.getIndex());
+ Libcore.os.bind(fd, addr);
+
+ PacketSocketAddress bound = (PacketSocketAddress) Libcore.os.getsockname(fd);
+ assertEquals((short) ETH_P_IPV6, bound.sll_protocol); // ETH_P_IPV6 is an int.
+ assertEquals(lo.getIndex(), bound.sll_ifindex);
+ assertEquals(ARPHRD_LOOPBACK, bound.sll_hatype);
+ assertEquals(0, bound.sll_pkttype);
+
+ // The loopback address is ETH_ALEN bytes long and is all zeros.
+ // http://lxr.free-electrons.com/source/drivers/net/loopback.c?v=3.10#L167
+ assertEquals(6, bound.sll_addr.length);
+ for (int i = 0; i < 6; i++) {
+ assertEquals(0, bound.sll_addr[i]);
+ }
+ }
+
+ public void test_byteBufferPositions_sendto_recvfrom_af_inet() throws Exception {
+ checkByteBufferPositions_sendto_recvfrom(AF_INET, InetAddress.getByName("127.0.0.1"));
+ }
+
+ public void test_byteBufferPositions_sendto_recvfrom_af_inet6() throws Exception {
+ checkByteBufferPositions_sendto_recvfrom(AF_INET6, InetAddress.getByName("::1"));
+ }
+
+ private void checkSendToSocketAddress(int family, InetAddress loopback) throws Exception {
+ FileDescriptor recvFd = Libcore.os.socket(family, SOCK_DGRAM, 0);
+ Libcore.os.bind(recvFd, loopback, 0);
+ StructTimeval tv = StructTimeval.fromMillis(20);
+ Libcore.os.setsockoptTimeval(recvFd, SOL_SOCKET, SO_RCVTIMEO, tv);
+
+ InetSocketAddress to = ((InetSocketAddress) Libcore.os.getsockname(recvFd));
+ FileDescriptor sendFd = Libcore.os.socket(family, SOCK_DGRAM, 0);
+ byte[] msg = ("Hello, I'm going to a socket address: " + to.toString()).getBytes("UTF-8");
+ int len = msg.length;
+
+ assertEquals(len, Libcore.os.sendto(sendFd, msg, 0, len, 0, to));
+ byte[] received = new byte[msg.length + 42];
+ InetSocketAddress from = new InetSocketAddress();
+ assertEquals(len, Libcore.os.recvfrom(recvFd, received, 0, received.length, 0, from));
+ assertEquals(loopback, from.getAddress());
+ }
+
+ public void test_sendtoSocketAddress_af_inet() throws Exception {
+ checkSendToSocketAddress(AF_INET, InetAddress.getByName("127.0.0.1"));
+ }
+
+ public void test_sendtoSocketAddress_af_inet6() throws Exception {
+ checkSendToSocketAddress(AF_INET6, InetAddress.getByName("::1"));
+ }
+
+ public void test_socketFamilies() throws Exception {
+ FileDescriptor fd = Libcore.os.socket(AF_INET6, SOCK_STREAM, 0);
+ Libcore.os.bind(fd, InetAddress.getByName("::"), 0);
+ InetSocketAddress localSocketAddress = (InetSocketAddress) Libcore.os.getsockname(fd);
+ assertEquals(Inet6Address.ANY, localSocketAddress.getAddress());
+
+ fd = Libcore.os.socket(AF_INET6, SOCK_STREAM, 0);
+ Libcore.os.bind(fd, InetAddress.getByName("0.0.0.0"), 0);
+ localSocketAddress = (InetSocketAddress) Libcore.os.getsockname(fd);
+ assertEquals(Inet6Address.ANY, localSocketAddress.getAddress());
+
+ fd = Libcore.os.socket(AF_INET, SOCK_STREAM, 0);
+ Libcore.os.bind(fd, InetAddress.getByName("0.0.0.0"), 0);
+ localSocketAddress = (InetSocketAddress) Libcore.os.getsockname(fd);
+ assertEquals(Inet4Address.ANY, localSocketAddress.getAddress());
+ try {
+ Libcore.os.bind(fd, InetAddress.getByName("::"), 0);
+ fail("Expected ErrnoException binding IPv4 socket to ::");
+ } catch (ErrnoException expected) {
+ assertEquals("Expected EAFNOSUPPORT binding IPv4 socket to ::", EAFNOSUPPORT, expected.errno);
+ }
+ }
+
+ private static void assertArrayEquals(byte[] expected, byte[] actual) {
+ assertTrue("Expected=" + Arrays.toString(expected) + ", actual=" + Arrays.toString(actual),
+ Arrays.equals(expected, actual));
+ }
+
+ private static void checkSocketPing(FileDescriptor fd, InetAddress to, byte[] packet,
+ byte type, byte responseType, boolean useSendto) throws Exception {
+ int len = packet.length;
+ packet[0] = type;
+ if (useSendto) {
+ assertEquals(len, Libcore.os.sendto(fd, packet, 0, len, 0, to, 0));
+ } else {
+ Libcore.os.connect(fd, to, 0);
+ assertEquals(len, Libcore.os.sendto(fd, packet, 0, len, 0, null, 0));
+ }
+
+ int icmpId = ((InetSocketAddress) Libcore.os.getsockname(fd)).getPort();
+ byte[] received = new byte[4096];
+ InetSocketAddress srcAddress = new InetSocketAddress();
+ assertEquals(len, Libcore.os.recvfrom(fd, received, 0, received.length, 0, srcAddress));
+ assertEquals(to, srcAddress.getAddress());
+ assertEquals(responseType, received[0]);
+ assertEquals(received[4], (byte) (icmpId >> 8));
+ assertEquals(received[5], (byte) (icmpId & 0xff));
+
+ received = Arrays.copyOf(received, len);
+ received[0] = (byte) type;
+ received[2] = received[3] = 0; // Checksum.
+ received[4] = received[5] = 0; // ICMP ID.
+ assertArrayEquals(packet, received);
+ }
+
+ public void test_socketPing() throws Exception {
+ final byte ICMP_ECHO = 8, ICMP_ECHOREPLY = 0;
+ final byte ICMPV6_ECHO_REQUEST = (byte) 128, ICMPV6_ECHO_REPLY = (byte) 129;
+ final byte[] packet = ("\000\000\000\000" + // ICMP type, code.
+ "\000\000\000\003" + // ICMP ID (== port), sequence number.
+ "Hello myself").getBytes(StandardCharsets.US_ASCII);
+
+ FileDescriptor fd = Libcore.os.socket(AF_INET6, SOCK_DGRAM, IPPROTO_ICMPV6);
+ InetAddress ipv6Loopback = InetAddress.getByName("::1");
+ checkSocketPing(fd, ipv6Loopback, packet, ICMPV6_ECHO_REQUEST, ICMPV6_ECHO_REPLY, true);
+ checkSocketPing(fd, ipv6Loopback, packet, ICMPV6_ECHO_REQUEST, ICMPV6_ECHO_REPLY, false);
+
+ fd = Libcore.os.socket(AF_INET, SOCK_DGRAM, IPPROTO_ICMP);
+ InetAddress ipv4Loopback = InetAddress.getByName("127.0.0.1");
+ checkSocketPing(fd, ipv4Loopback, packet, ICMP_ECHO, ICMP_ECHOREPLY, true);
+ checkSocketPing(fd, ipv4Loopback, packet, ICMP_ECHO, ICMP_ECHOREPLY, false);
+ }
+
+ private static void assertPartial(byte[] expected, byte[] actual) {
+ for (int i = 0; i < expected.length; i++) {
+ if (expected[i] != actual[i]) {
+ fail("Expected " + Arrays.toString(expected) + " but found "
+ + Arrays.toString(actual));
+ }
+ }
+ }
+
+ public void test_xattr() throws Exception {
+ final String NAME_TEST = "user.meow";
+
+ final byte[] VALUE_CAKE = "cake cake cake".getBytes(StandardCharsets.UTF_8);
+ final byte[] VALUE_PIE = "pie".getBytes(StandardCharsets.UTF_8);
+
+ File file = File.createTempFile("xattr", "test");
+ String path = file.getAbsolutePath();
+
+ byte[] tmp = new byte[1024];
+ try {
+ try {
+ Libcore.os.getxattr(path, NAME_TEST, tmp);
+ fail("Expected ENODATA");
+ } catch (ErrnoException e) {
+ assertEquals(OsConstants.ENODATA, e.errno);
+ }
+
+ Libcore.os.setxattr(path, NAME_TEST, VALUE_CAKE, OsConstants.XATTR_CREATE);
+ assertEquals(VALUE_CAKE.length, Libcore.os.getxattr(path, NAME_TEST, tmp));
+ assertPartial(VALUE_CAKE, tmp);
+
+ try {
+ Libcore.os.setxattr(path, NAME_TEST, VALUE_PIE, OsConstants.XATTR_CREATE);
+ fail("Expected EEXIST");
+ } catch (ErrnoException e) {
+ assertEquals(OsConstants.EEXIST, e.errno);
+ }
+
+ Libcore.os.setxattr(path, NAME_TEST, VALUE_PIE, OsConstants.XATTR_REPLACE);
+ assertEquals(VALUE_PIE.length, Libcore.os.getxattr(path, NAME_TEST, tmp));
+ assertPartial(VALUE_PIE, tmp);
+
+ Libcore.os.removexattr(path, NAME_TEST);
+ try {
+ Libcore.os.getxattr(path, NAME_TEST, tmp);
+ fail("Expected ENODATA");
+ } catch (ErrnoException e) {
+ assertEquals(OsConstants.ENODATA, e.errno);
+ }
+
+ } finally {
+ file.delete();
+ }
+ }
}
diff --git a/luni/src/test/java/libcore/java/io/FileDescriptorTest.java b/luni/src/test/java/libcore/java/io/FileDescriptorTest.java
index 39472df..e2780c9 100644
--- a/luni/src/test/java/libcore/java/io/FileDescriptorTest.java
+++ b/luni/src/test/java/libcore/java/io/FileDescriptorTest.java
@@ -30,14 +30,14 @@ public class FileDescriptorTest extends TestCase {
new RandomAccessFile(f, "r").getFD().sync();
}
- public void test_isSocket() throws Exception {
+ public void test_isSocket$() throws Exception {
File f = new File("/dev/null");
FileInputStream fis = new FileInputStream(f);
- assertFalse(fis.getFD().isSocket());
+ assertFalse(fis.getFD().isSocket$());
fis.close();
ServerSocket s = new ServerSocket();
- assertTrue(s.getImpl$().getFD$().isSocket());
+ assertTrue(s.getImpl$().getFD$().isSocket$());
s.close();
}
}
diff --git a/luni/src/test/java/libcore/java/io/FileInputStreamTest.java b/luni/src/test/java/libcore/java/io/FileInputStreamTest.java
index 14950ee..26de11a 100644
--- a/luni/src/test/java/libcore/java/io/FileInputStreamTest.java
+++ b/luni/src/test/java/libcore/java/io/FileInputStreamTest.java
@@ -67,7 +67,7 @@ public final class FileInputStreamTest extends TestCase {
}
public void testSkipInPipes() throws Exception {
- FileDescriptor[] pipe = Libcore.os.pipe();
+ FileDescriptor[] pipe = Libcore.os.pipe2(0);
DataFeeder feeder = new DataFeeder(pipe[1]);
try {
feeder.start();
diff --git a/luni/src/test/java/libcore/java/io/RandomAccessFileTest.java b/luni/src/test/java/libcore/java/io/RandomAccessFileTest.java
index afe49b7..8d99457 100644
--- a/luni/src/test/java/libcore/java/io/RandomAccessFileTest.java
+++ b/luni/src/test/java/libcore/java/io/RandomAccessFileTest.java
@@ -20,6 +20,8 @@ import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.RandomAccessFile;
+import java.nio.channels.FileChannel;
+
import junit.framework.TestCase;
import libcore.java.lang.ref.FinalizationTester;
@@ -73,6 +75,61 @@ public final class RandomAccessFileTest extends TestCase {
FinalizationTester.induceFinalization();
}
}
+
+ // http://b/19892782
+ public void testCloseRaf_sameChannelReturned() throws Exception {
+ RandomAccessFile raf = new RandomAccessFile(file, "rw");
+
+ FileChannel fileChannelBeforeClosing = raf.getChannel();
+ raf.close();
+ FileChannel fileChannelAfterClosing = raf.getChannel();
+ assertSame(fileChannelBeforeClosing, fileChannelAfterClosing);
+ }
+
+ // http://b/19892782
+ public void testCloseRaf_channelIsClosed() throws Exception {
+ RandomAccessFile raf = new RandomAccessFile(file, "rw");
+
+ FileChannel fileChannelBeforeClosing = raf.getChannel();
+ raf.close();
+ FileChannel fileChannelAfterClosing = raf.getChannel();
+ assertFalse(fileChannelBeforeClosing.isOpen());
+ }
+
+ // http://b/19892782
+ public void testCloseFileChannel_sameChannelReturned() throws Exception {
+ RandomAccessFile raf = new RandomAccessFile(file, "rw");
+
+ FileChannel fileChannelBeforeClosing = raf.getChannel();
+ fileChannelBeforeClosing.close();
+
+ FileChannel fileChannelAfterClosing = raf.getChannel();
+ assertSame(fileChannelBeforeClosing, fileChannelAfterClosing);
+ }
+
+ // http://b/19892782
+ public void testCloseFileChannel_returnedFileChannelIsClosed() throws Exception {
+ RandomAccessFile raf = new RandomAccessFile(file, "rw");
+
+ FileChannel fileChannelBeforeClosing = raf.getChannel();
+ // This should close the Raf, and previous implementations wrongly returned a new
+ // open (but useless) channel in this case.
+ fileChannelBeforeClosing.close();
+ FileChannel fileChannelAfterClosing = raf.getChannel();
+ assertFalse(fileChannelBeforeClosing.isOpen());
+ }
+
+ // http://b/19892782
+ public void testCloseRafBeforeGetChannel_returnChannelWithCloseFdAfterClose() throws Exception {
+ RandomAccessFile raf = new RandomAccessFile(file, "rw");
+ raf.close();
+ try {
+ raf.getChannel().size();
+ fail();
+ } catch (IOException expected) {
+ }
+ }
+
private void createRandomAccessFile(File file) throws Exception {
// TODO: fix our register maps and remove this otherwise unnecessary
// indirection! (http://b/5412580)
diff --git a/luni/src/test/java/libcore/java/lang/FloatTest.java b/luni/src/test/java/libcore/java/lang/FloatTest.java
index 92e7ae4..c25bd5c 100644
--- a/luni/src/test/java/libcore/java/lang/FloatTest.java
+++ b/luni/src/test/java/libcore/java/lang/FloatTest.java
@@ -121,4 +121,20 @@ public class FloatTest extends junit.framework.TestCase {
}
assertEquals(f1, 0f);
}
+
+ // Float equivalent of testParseLargestSubnormalDoublePrecision. http://b/18087920.
+ public void testParseLargestSubnormalFloatPrecision() {
+ // These are different ways of saying MIN_NORMAL.
+ assertEquals(1.1754943508222875e-38f, Float.parseFloat("1.1754943508222875e-38"));
+ assertEquals(1.1754943508222875e-38f, Float.parseFloat("0.00011754943508222875e-34f"));
+ assertEquals(1.1754943508222875e-38f, Float.parseFloat("00000001.1754943508222875e-38f"));
+ assertEquals(1.1754943508222875e-38f, Float.parseFloat("1.17549435082228750000e-38f"));
+ assertEquals(1.1754943508222875e-38f, Float.parseFloat("1.1754943508222875e-0038f"));
+ assertEquals(-1.1754943508222875e-38f, Float.parseFloat("-1.1754943508222875e-38f"));
+
+ // Extra interesting values suggested as part of http://b/18087920.
+ assertEquals(1.1754944e-38f, Float.parseFloat("11754942807573643E-54"));
+ assertEquals(1.1754944e-38f, Float.parseFloat("11754942807573644E-54"));
+ assertEquals(1.1754944e-38f, Float.parseFloat("11754942807573645E-54"));
+ }
}
diff --git a/luni/src/test/java/libcore/java/lang/OldAndroidMonitorTest.java b/luni/src/test/java/libcore/java/lang/OldAndroidMonitorTest.java
index d1704fb..4760c6d 100644..100755
--- a/luni/src/test/java/libcore/java/lang/OldAndroidMonitorTest.java
+++ b/luni/src/test/java/libcore/java/lang/OldAndroidMonitorTest.java
@@ -103,7 +103,7 @@ public class OldAndroidMonitorTest extends TestCase {
}
private class Interrupter extends Thread {
- Waiter waiter;
+ private final Waiter waiter;
Interrupter(String name, Waiter waiter) {
super(name);
@@ -119,8 +119,7 @@ public class OldAndroidMonitorTest extends TestCase {
}
}
- void run_inner() {
- waiter.spin = true;
+ private void run_inner() {
// System.out.println("InterruptTest: starting waiter");
waiter.start();
@@ -168,7 +167,7 @@ public class OldAndroidMonitorTest extends TestCase {
private class Waiter extends Thread {
Object interrupterLock = new Object();
- Boolean spin = false;
+ volatile boolean spin = true;
Waiter(String name) {
super(name);
@@ -188,6 +187,7 @@ public class OldAndroidMonitorTest extends TestCase {
while (spin) {
// We're going to get interrupted while we spin.
}
+
if (interrupted()) {
// System.out.println("Waiter done spinning; interrupted.");
} else {
@@ -196,7 +196,7 @@ public class OldAndroidMonitorTest extends TestCase {
}
synchronized (this) {
- Boolean sawEx = false;
+ boolean sawEx = false;
try {
synchronized (interrupterLock) {
@@ -216,7 +216,7 @@ public class OldAndroidMonitorTest extends TestCase {
}
}
synchronized (this) {
- Boolean sawEx = false;
+ boolean sawEx = false;
try {
synchronized (interrupterLock) {
@@ -236,7 +236,7 @@ public class OldAndroidMonitorTest extends TestCase {
}
}
synchronized (this) {
- Boolean sawEx = false;
+ boolean sawEx = false;
try {
synchronized (interrupterLock) {
diff --git a/luni/src/test/java/libcore/java/lang/OldClassTest.java b/luni/src/test/java/libcore/java/lang/OldClassTest.java
index 23a42bd..f5bc787 100644
--- a/luni/src/test/java/libcore/java/lang/OldClassTest.java
+++ b/luni/src/test/java/libcore/java/lang/OldClassTest.java
@@ -40,11 +40,6 @@ import tests.support.resource.Support_Resources;
@SuppressWarnings("deprecation")
public class OldClassTest extends junit.framework.TestCase {
-
- public static final String FILENAME =
- OldClassTest.class.getPackage().getName().replace('.', '/') +
- "/test#.properties";
-
final String packageName = getClass().getPackage().getName();
final String classNameInitError1 = packageName + ".TestClass1";
final String classNameInitError2 = packageName + ".TestClass1B";
diff --git a/luni/src/test/java/libcore/java/lang/OldSystemTest.java b/luni/src/test/java/libcore/java/lang/OldSystemTest.java
index dee5bdd..93b06c8 100644
--- a/luni/src/test/java/libcore/java/lang/OldSystemTest.java
+++ b/luni/src/test/java/libcore/java/lang/OldSystemTest.java
@@ -260,12 +260,14 @@ public class OldSystemTest extends junit.framework.TestCase {
while(rt.freeMemory() < beforeTest * 2/3) {
vec.add(new StringBuffer(1000));
}
- long beforeGC = rt.freeMemory();
+ long beforeGC = rt.totalMemory() - rt.freeMemory();
+ vec = null;
System.gc();
- long afterGC = rt.freeMemory();
+ System.runFinalization();
+ long afterGC = rt.totalMemory() - rt.freeMemory();
assertTrue("memory was not released after calling System.gc()." +
"before gc: " + beforeGC + "; after gc: " + afterGC,
- beforeGC < afterGC);
+ beforeGC > afterGC);
}
public void test_getenv() {
diff --git a/luni/src/test/java/libcore/java/lang/PackageTest.java b/luni/src/test/java/libcore/java/lang/PackageTest.java
index 6e274a0..c004e23 100644
--- a/luni/src/test/java/libcore/java/lang/PackageTest.java
+++ b/luni/src/test/java/libcore/java/lang/PackageTest.java
@@ -25,9 +25,10 @@ public final class PackageTest extends TestCase {
private static final List<Package> packages = Arrays.asList(Package.getPackages());
public void test_getAnnotations() throws Exception {
- // Package annotations aren't supported, but pre-ICS we crashed.
- assertEquals(0, getClass().getPackage().getAnnotations().length);
- assertEquals(0, getClass().getPackage().getDeclaredAnnotations().length);
+ // Pre-ICS we crashed. To pass, the package-info and TestPackageAnnotation classes must be
+ // on the classpath.
+ assertEquals(1, getClass().getPackage().getAnnotations().length);
+ assertEquals(1, getClass().getPackage().getDeclaredAnnotations().length);
}
public void testGetPackage() {
diff --git a/luni/src/test/java/libcore/java/lang/ProcessBuilderTest.java b/luni/src/test/java/libcore/java/lang/ProcessBuilderTest.java
index 9766cef..51aed38 100644
--- a/luni/src/test/java/libcore/java/lang/ProcessBuilderTest.java
+++ b/luni/src/test/java/libcore/java/lang/ProcessBuilderTest.java
@@ -28,7 +28,7 @@ import static tests.support.Support_Exec.execAndCheckOutput;
public class ProcessBuilderTest extends AbstractResourceLeakageDetectorTestCase {
private static String shell() {
- String deviceSh = "/system/bin/sh";
+ String deviceSh = System.getenv("ANDROID_ROOT") + "/bin/sh";
String desktopSh = "/bin/sh";
return new File(deviceSh).exists() ? deviceSh : desktopSh;
}
diff --git a/luni/src/test/java/libcore/java/lang/StringTest.java b/luni/src/test/java/libcore/java/lang/StringTest.java
index bf162e5..bd52e06 100644
--- a/luni/src/test/java/libcore/java/lang/StringTest.java
+++ b/luni/src/test/java/libcore/java/lang/StringTest.java
@@ -173,47 +173,6 @@ public class StringTest extends TestCase {
}
/**
- * Tests a widely assumed performance characteristic of String.substring():
- * that it reuses the original's backing array. Although behavior should be
- * correct even if this test fails, many applications may suffer
- * significant performance degradation.
- */
- public void testSubstringSharesBackingArray() throws IllegalAccessException {
- String abcdefghij = "ABCDEFGHIJ";
- String cdefg = abcdefghij.substring(2, 7);
- assertSame(getBackingArray(abcdefghij), getBackingArray(cdefg));
- }
-
- /**
- * Tests a widely assumed performance characteristic of string's copy
- * constructor: that it ensures the backing array is the same length as the
- * string. Although behavior should be correct even if this test fails,
- * many applications may suffer significant performance degradation.
- */
- public void testStringCopiesAvoidHeapRetention() throws IllegalAccessException {
- String abcdefghij = "ABCDEFGHIJ";
- assertSame(getBackingArray(abcdefghij), getBackingArray(new String(abcdefghij)));
-
- String cdefg = abcdefghij.substring(2, 7);
- assertSame(getBackingArray(abcdefghij), getBackingArray(cdefg));
- assertEquals(5, getBackingArray(new String(cdefg)).length);
- }
-
- /**
- * Uses reflection to return the char[] backing the given string. This
- * returns the actual backing array; which must not be modified.
- */
- private char[] getBackingArray(String string) throws IllegalAccessException {
- for (Field f : String.class.getDeclaredFields()) {
- if (!Modifier.isStatic(f.getModifiers()) && f.getType() == char[].class) {
- f.setAccessible(true);
- return (char[]) f.get(string);
- }
- }
- throw new UnsupportedOperationException("No chars[] field on String!");
- }
-
- /**
* Test that strings interned manually and then later loaded as literals
* maintain reference equality. http://b/3098960
*/
diff --git a/luni/src/test/java/libcore/java/lang/TestPackageAnnotation.java b/luni/src/test/java/libcore/java/lang/TestPackageAnnotation.java
new file mode 100644
index 0000000..7626206
--- /dev/null
+++ b/luni/src/test/java/libcore/java/lang/TestPackageAnnotation.java
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package libcore.java.lang;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+// Used by PackageTest
+@Target(ElementType.PACKAGE)
+@Retention(RetentionPolicy.RUNTIME)
+public @interface TestPackageAnnotation {}
diff --git a/luni/src/test/java/libcore/java/lang/package-info.java b/luni/src/test/java/libcore/java/lang/package-info.java
new file mode 100644
index 0000000..d916e9a
--- /dev/null
+++ b/luni/src/test/java/libcore/java/lang/package-info.java
@@ -0,0 +1,18 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+// Used by PackageTest
+@TestPackageAnnotation
+package libcore.java.lang; \ No newline at end of file
diff --git a/luni/src/test/java/libcore/java/lang/reflect/FieldTest.java b/luni/src/test/java/libcore/java/lang/reflect/FieldTest.java
index b60d984..75665db 100644
--- a/luni/src/test/java/libcore/java/lang/reflect/FieldTest.java
+++ b/luni/src/test/java/libcore/java/lang/reflect/FieldTest.java
@@ -17,6 +17,8 @@
package libcore.java.lang.reflect;
import java.lang.reflect.Field;
+import java.lang.reflect.Modifier;
+
import junit.framework.TestCase;
public final class FieldTest extends TestCase {
@@ -46,6 +48,56 @@ public final class FieldTest extends TestCase {
assertFalse(f1.equals(f2));
}
+ // Tests that the "synthetic" modifier is handled correctly.
+ // It's supposed to be present but not shown in toString.
+ public void testSyntheticModifier() throws NoSuchFieldException {
+ Field valuesField = Thread.State.class.getDeclaredField("$VALUES");
+ // Check that this test makes sense.
+ assertTrue(valuesField.isSynthetic());
+ assertEquals(Modifier.SYNTHETIC, valuesField.getModifiers() & Modifier.SYNTHETIC);
+ assertEquals("private static final java.lang.Thread$State[] java.lang.Thread$State.$VALUES",
+ valuesField.toString());
+ }
+
+ // Ensure that the "enum constant" bit is not returned in toString.
+ public void testEnumValueField() throws NoSuchFieldException {
+ Field blockedField = Thread.State.class.getDeclaredField("BLOCKED");
+ assertTrue(Thread.State.class.getDeclaredField("BLOCKED").isEnumConstant());
+ assertEquals("public static final", Modifier.toString(blockedField.getModifiers()));
+ assertEquals(
+ "public static final java.lang.Thread$State java.lang.Thread$State.BLOCKED",
+ blockedField.toString());
+ }
+
+ class ClassWithATransientField {
+ private transient Class<String> transientField = String.class;
+ }
+
+ // Tests that the "transient" modifier is handled correctly.
+ // The underlying constant value for it is the same as for the "varargs" method modifier.
+ // http://b/18488857
+ public void testTransientModifier() throws NoSuchFieldException {
+ Field transientField = ClassWithATransientField.class.getDeclaredField("transientField");
+ // Check that this test makes sense.
+ assertEquals(Modifier.TRANSIENT, transientField.getModifiers() & Modifier.TRANSIENT);
+ assertEquals(
+ "private transient java.lang.Class "
+ + "libcore.java.lang.reflect.FieldTest$ClassWithATransientField"
+ + ".transientField",
+ transientField.toString());
+ }
+
+ public void testToGenericString() throws NoSuchFieldException {
+ Field transientField = ClassWithATransientField.class.getDeclaredField("transientField");
+ // Check that this test makes sense.
+ assertEquals(Modifier.TRANSIENT, transientField.getModifiers() & Modifier.TRANSIENT);
+ assertEquals(
+ "private transient java.lang.Class<java.lang.String> "
+ + "libcore.java.lang.reflect.FieldTest$ClassWithATransientField"
+ + ".transientField",
+ transientField.toGenericString());
+ }
+
static class FieldTestHelper {
public String a;
public Object b;
diff --git a/luni/src/test/java/libcore/java/lang/reflect/MethodTest.java b/luni/src/test/java/libcore/java/lang/reflect/MethodTest.java
index c3a436c..a3f9065 100644
--- a/luni/src/test/java/libcore/java/lang/reflect/MethodTest.java
+++ b/luni/src/test/java/libcore/java/lang/reflect/MethodTest.java
@@ -17,6 +17,7 @@
package libcore.java.lang.reflect;
import java.lang.reflect.Method;
+
import junit.framework.TestCase;
public final class MethodTest extends TestCase {
@@ -197,6 +198,23 @@ public final class MethodTest extends TestCase {
assertEquals( "public java.lang.Process java.lang.Runtime.exec(java.lang.String[])"
+ " throws java.io.IOException",
Runtime.class.getMethod("exec", new Class[] { String[].class }).toString());
+ // http://b/18488857
+ assertEquals(
+ "public int java.lang.String.compareTo(java.lang.Object)",
+ String.class.getMethod("compareTo", Object.class).toString());
+ }
+
+ // Tests that the "varargs" modifier is handled correctly.
+ // The underlying constant value for it is the same as for the "transient" field modifier.
+ // http://b/18488857
+ public void testVarargsModifier() throws NoSuchMethodException {
+ Method stringFormatMethod = String.class.getMethod(
+ "format", new Class[] { String.class, Object[].class });
+ assertTrue(stringFormatMethod.isVarArgs());
+ assertEquals(
+ "public static java.lang.String java.lang.String.format("
+ + "java.lang.String,java.lang.Object[])",
+ stringFormatMethod.toString());
}
public static class MethodTestHelper {
diff --git a/luni/src/test/java/libcore/java/lang/reflect/ModifierTest.java b/luni/src/test/java/libcore/java/lang/reflect/ModifierTest.java
index 1bde157..0505f2f 100644
--- a/luni/src/test/java/libcore/java/lang/reflect/ModifierTest.java
+++ b/luni/src/test/java/libcore/java/lang/reflect/ModifierTest.java
@@ -100,6 +100,9 @@ public class ModifierTest extends junit.framework.TestCase {
}
public void test_toStringI() {
- assertEquals("public abstract", Modifier.toString(Modifier.PUBLIC | Modifier.ABSTRACT));
+ // Note that it checks that "STRICT" is rendered as "strictfp" (for other modifiers,
+ // the displayed name is the same as the lowercase constant name).
+ assertEquals("public abstract strictfp",
+ Modifier.toString(Modifier.PUBLIC | Modifier.ABSTRACT | Modifier.STRICT));
}
}
diff --git a/luni/src/test/java/libcore/java/net/InetAddressTest.java b/luni/src/test/java/libcore/java/net/InetAddressTest.java
index 4b656cc..8bdcf64 100644
--- a/luni/src/test/java/libcore/java/net/InetAddressTest.java
+++ b/luni/src/test/java/libcore/java/net/InetAddressTest.java
@@ -21,10 +21,14 @@ import java.net.Inet6Address;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.UnknownHostException;
+import java.util.Arrays;
import java.util.Collections;
+import java.util.HashSet;
+import java.util.Set;
import libcore.util.SerializationTester;
public class InetAddressTest extends junit.framework.TestCase {
+ private static final byte[] LOOPBACK4_BYTES = new byte[] { 127, 0, 0, 1 };
private static final byte[] LOOPBACK6_BYTES = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 };
private static final String[] INVALID_IPv4_NUMERIC_ADDRESSES = new String[] {
@@ -72,7 +76,7 @@ public class InetAddressTest extends junit.framework.TestCase {
}
private static Inet6Address localhost6() throws Exception {
- return (Inet6Address) InetAddress.getByAddress("localhost", LOOPBACK6_BYTES);
+ return (Inet6Address) InetAddress.getByAddress("ip6-localhost", LOOPBACK6_BYTES);
}
public void test_parseNumericAddress() throws Exception {
@@ -311,4 +315,84 @@ public class InetAddressTest extends junit.framework.TestCase {
assertEquals(resultStrings[i], result);
}
}
+
+ public void test_getHostNameCaches() throws Exception {
+ InetAddress inetAddress = InetAddress.getByAddress(LOOPBACK6_BYTES);
+ assertEquals("::1", inetAddress.getHostString());
+ assertEquals("ip6-localhost", inetAddress.getHostName());
+ // getHostString() should now be different.
+ assertEquals("ip6-localhost", inetAddress.getHostString());
+ }
+
+ public void test_getByAddress_loopbackIpv4() throws Exception {
+ InetAddress inetAddress = InetAddress.getByAddress(LOOPBACK4_BYTES);
+ assertEquals(LOOPBACK4_BYTES, "localhost", inetAddress);
+ assertTrue(inetAddress.isLoopbackAddress());
+ }
+
+ public void test_getByAddress_loopbackIpv6() throws Exception {
+ InetAddress inetAddress = InetAddress.getByAddress(LOOPBACK6_BYTES);
+ assertEquals(LOOPBACK6_BYTES, "ip6-localhost", inetAddress);
+ assertTrue(inetAddress.isLoopbackAddress());
+ }
+
+ public void test_getByName_loopbackIpv4() throws Exception {
+ InetAddress inetAddress = InetAddress.getByName("127.0.0.1");
+ assertEquals(LOOPBACK4_BYTES, "localhost", inetAddress);
+ assertTrue(inetAddress.isLoopbackAddress());
+ }
+
+ public void test_getByName_loopbackIpv6() throws Exception {
+ InetAddress inetAddress = InetAddress.getByName("::1");
+ assertEquals(LOOPBACK6_BYTES, "ip6-localhost", inetAddress);
+ assertTrue(inetAddress.isLoopbackAddress());
+ }
+
+ public void test_getAllByName_localhost() throws Exception {
+ InetAddress[] inetAddresses = InetAddress.getAllByName("localhost");
+ assertEquals(1, inetAddresses.length);
+ InetAddress inetAddress = inetAddresses[0];
+ assertEquals(LOOPBACK4_BYTES, "localhost", inetAddress);
+ assertTrue(inetAddress.isLoopbackAddress());
+ }
+
+ public void test_getAllByName_ip6_localhost() throws Exception {
+ InetAddress[] inetAddresses = InetAddress.getAllByName("ip6-localhost");
+ assertEquals(1, inetAddresses.length);
+ InetAddress inetAddress = inetAddresses[0];
+ assertEquals(LOOPBACK6_BYTES, "ip6-localhost", inetAddress);
+ assertTrue(inetAddress.isLoopbackAddress());
+ }
+
+ public void test_getByName_null() throws Exception {
+ InetAddress inetAddress = InetAddress.getByName("::1");
+
+ Set<InetAddress> expectedLoopbackAddresses =
+ createSet(Inet4Address.LOOPBACK, Inet6Address.LOOPBACK);
+ assertTrue(expectedLoopbackAddresses.contains(inetAddress));
+ }
+
+ public void test_getAllByName_null() throws Exception {
+ InetAddress[] inetAddresses = InetAddress.getAllByName(null);
+ assertEquals(2, inetAddresses.length);
+ Set<InetAddress> expectedLoopbackAddresses =
+ createSet(Inet4Address.LOOPBACK, Inet6Address.LOOPBACK);
+ assertEquals(expectedLoopbackAddresses, createSet(inetAddresses));
+ }
+
+ private static void assertEquals(
+ byte[] expectedAddressBytes, String expectedHostname, InetAddress actual) {
+ assertArrayEquals(expectedAddressBytes, actual.getAddress());
+ assertEquals(expectedHostname, actual.getHostName());
+
+ }
+
+ private static void assertArrayEquals(byte[] expected, byte[] actual) {
+ assertTrue("Expected=" + Arrays.toString(expected) + ", actual=" + Arrays.toString(actual),
+ Arrays.equals(expected, actual));
+ }
+
+ private static Set<InetAddress> createSet(InetAddress... members) {
+ return new HashSet<InetAddress>(Arrays.asList(members));
+ }
}
diff --git a/luni/src/test/java/libcore/java/net/InetSocketAddressTest.java b/luni/src/test/java/libcore/java/net/InetSocketAddressTest.java
index 3bca8dc..d97c48a 100644
--- a/luni/src/test/java/libcore/java/net/InetSocketAddressTest.java
+++ b/luni/src/test/java/libcore/java/net/InetSocketAddressTest.java
@@ -63,7 +63,7 @@ public class InetSocketAddressTest extends TestCase {
}
InetSocketAddress isa = new InetSocketAddress((InetAddress)null, 80);
- assertEquals("0.0.0.0", isa.getHostName());
+ assertEquals("::", isa.getHostName());
try {
new InetSocketAddress(InetAddress.getByName("localhost"), 65536);
@@ -80,7 +80,7 @@ public class InetSocketAddressTest extends TestCase {
public void test_ConstructorI() {
InetSocketAddress isa = new InetSocketAddress(65535);
- assertEquals("0.0.0.0", isa.getHostName());
+ assertEquals("::", isa.getHostName());
assertEquals(65535, isa.getPort());
try {
@@ -150,6 +150,20 @@ public class InetSocketAddressTest extends TestCase {
assertTrue(hasHostname.isUnresolved());
assertEquals("some host", hasHostname.getHostString());
assertEquals("some host", hasHostname.getHostName());
+
+ InetSocketAddress hasHostnameAndAddress = new InetSocketAddress(
+ InetAddress.getByAddress("some host", new byte[] { 127, 0, 0, 1 }),
+ 1234);
+ assertFalse(hasHostnameAndAddress.isUnresolved());
+ assertEquals("some host", hasHostnameAndAddress.getHostString());
+ assertEquals("some host", hasHostnameAndAddress.getHostName());
+
+ // Using a host name that is actually an IP.
+ InetSocketAddress hostnameIsIp = InetSocketAddress.createUnresolved("127.0.0.1", 1234);
+ assertTrue(hostnameIsIp.isUnresolved());
+ assertEquals("127.0.0.1", hostnameIsIp.getHostString());
+ assertEquals("127.0.0.1", hostnameIsIp.getHostName());
+
// When we don't have a hostname, whether or not we do the reverse lookup is the difference
// between getHostString and getHostName...
InetAddress address = InetAddress.getByAddress(new byte[] { 127, 0, 0, 1 });
@@ -157,4 +171,18 @@ public class InetSocketAddressTest extends TestCase {
assertEquals("127.0.0.1", noHostname.getHostString());
assertEquals("localhost", noHostname.getHostName());
}
+
+ public void test_getHostString_cachingBehavior() throws Exception {
+ InetAddress inetAddress = InetAddress.getByAddress(new byte[] { 127, 0, 0, 1 });
+ InetSocketAddress socketAddress = new InetSocketAddress(inetAddress, 1234);
+ assertEquals("127.0.0.1", socketAddress.getHostString());
+ assertEquals("localhost", socketAddress.getHostName());
+ assertEquals("localhost", socketAddress.getHostString());
+
+ inetAddress = InetAddress.getByName("127.0.0.1");
+ socketAddress = new InetSocketAddress(inetAddress, 1234);
+ assertEquals("127.0.0.1", socketAddress.getHostString());
+ assertEquals("localhost", socketAddress.getHostName());
+ assertEquals("localhost", socketAddress.getHostString());
+ }
}
diff --git a/luni/src/test/java/libcore/java/net/OldSocketTest.java b/luni/src/test/java/libcore/java/net/OldSocketTest.java
index 7973965..ded5802 100644
--- a/luni/src/test/java/libcore/java/net/OldSocketTest.java
+++ b/luni/src/test/java/libcore/java/net/OldSocketTest.java
@@ -37,6 +37,7 @@ import java.net.UnknownHostException;
import java.nio.channels.IllegalBlockingModeException;
import java.nio.channels.SocketChannel;
import java.security.Permission;
+import tests.net.StuckServer;
import tests.support.Support_Configuration;
public class OldSocketTest extends OldSocketTestCase {
@@ -932,25 +933,15 @@ public class OldSocketTest extends OldSocketTestCase {
}
// start by validating the error checks
- int portNumber = 0;
- Socket theSocket = null;
- ServerSocket serverSocket = null;
- SocketAddress theAddress = null;
- SocketAddress nonConnectableAddress = null;
- SocketAddress nonReachableAddress = null;
- SocketAddress invalidType = null;
- // byte[] theBytes = {-1,-1,-1,-1};
- byte[] theBytes = { 0, 0, 0, 0 };
- theAddress = new InetSocketAddress(InetAddress.getLocalHost(),
- portNumber);
- nonConnectableAddress = new InetSocketAddress(InetAddress
- .getByAddress(theBytes), portNumber);
- nonReachableAddress = new InetSocketAddress(InetAddress
- .getByName(Support_Configuration.ResolvedNotExistingHost),
- portNumber);
- invalidType = new mySocketAddress();
+ byte[] theBytes = { 0, 0, 0, 0 };
+ SocketAddress theAddress = new InetSocketAddress(InetAddress.getLocalHost(), 0);
+ SocketAddress nonConnectableAddress = new InetSocketAddress(InetAddress.getByAddress(theBytes), 0);
+ SocketAddress nonReachableAddress = new InetSocketAddress(StuckServer.UNREACHABLE_ADDRESS, 0);
+ SocketAddress invalidType = new mySocketAddress();
+ Socket theSocket = null;
+ ServerSocket serverSocket = null;
try {
theSocket = new Socket();
theSocket.connect(null);
@@ -1165,7 +1156,7 @@ public class OldSocketTest extends OldSocketTestCase {
byte[] theBytes = { 0, 0, 0, 0 };
SocketAddress theAddress = new InetSocketAddress(InetAddress.getLocalHost(), 0);
SocketAddress nonConnectableAddress = new InetSocketAddress(InetAddress.getByAddress(theBytes), 0);
- SocketAddress nonReachableAddress = new InetSocketAddress(InetAddress.getByName(Support_Configuration.ResolvedNotExistingHost), 0);
+ SocketAddress nonReachableAddress = new InetSocketAddress(StuckServer.UNREACHABLE_ADDRESS, 0);
SocketAddress invalidType = new mySocketAddress();
Socket theSocket = null;
diff --git a/luni/src/test/java/libcore/java/net/SocketTest.java b/luni/src/test/java/libcore/java/net/SocketTest.java
index fb09be0..9765a45 100644
--- a/luni/src/test/java/libcore/java/net/SocketTest.java
+++ b/luni/src/test/java/libcore/java/net/SocketTest.java
@@ -31,9 +31,11 @@ import java.net.SocketImpl;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.concurrent.Callable;
+import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
+import java.util.concurrent.TimeUnit;
public class SocketTest extends junit.framework.TestCase {
// See http://b/2980559.
@@ -353,6 +355,37 @@ public class SocketTest extends junit.framework.TestCase {
assertEquals(boundAddress.getPort(), localAddressAfterClose.getPort());
}
+ public void testCloseDuringConnect() throws Exception {
+ final CountDownLatch signal = new CountDownLatch(1);
+
+ final Socket s = new Socket();
+ new Thread() {
+ @Override
+ public void run() {
+ try {
+ // This address is reserved for documentation: should never be reachable.
+ InetSocketAddress unreachableIp = new InetSocketAddress("192.0.2.0", 80);
+ // This should never return.
+ s.connect(unreachableIp, 0 /* infinite */);
+ fail("Connect returned unexpectedly for: " + unreachableIp);
+ } catch (SocketException expected) {
+ assertTrue(expected.getMessage().contains("Socket closed"));
+ signal.countDown();
+ } catch (IOException e) {
+ fail("Unexpected exception: " + e);
+ }
+ }
+ }.start();
+
+ // Wait for the connect() thread to run and start connect()
+ Thread.sleep(2000);
+
+ s.close();
+
+ boolean connectUnblocked = signal.await(2000, TimeUnit.MILLISECONDS);
+ assertTrue(connectUnblocked);
+ }
+
static class MockServer {
private ExecutorService executor;
private ServerSocket serverSocket;
diff --git a/luni/src/test/java/libcore/java/net/URLConnectionTest.java b/luni/src/test/java/libcore/java/net/URLConnectionTest.java
index c09939f..3f831e0 100644
--- a/luni/src/test/java/libcore/java/net/URLConnectionTest.java
+++ b/luni/src/test/java/libcore/java/net/URLConnectionTest.java
@@ -16,7 +16,8 @@
package libcore.java.net;
-import com.android.okhttp.HttpResponseCache;
+import com.android.okhttp.AndroidShimResponseCache;
+
import com.google.mockwebserver.MockResponse;
import com.google.mockwebserver.MockWebServer;
import com.google.mockwebserver.RecordedRequest;
@@ -37,11 +38,14 @@ import java.net.ProtocolException;
import java.net.Proxy;
import java.net.ResponseCache;
import java.net.Socket;
+import java.net.SocketAddress;
+import java.net.SocketException;
import java.net.SocketTimeoutException;
import java.net.URI;
import java.net.URL;
import java.net.URLConnection;
import java.net.UnknownHostException;
+import java.nio.channels.SocketChannel;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
@@ -58,18 +62,18 @@ import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicReference;
import java.util.zip.GZIPInputStream;
import java.util.zip.GZIPOutputStream;
-import javax.net.SocketFactory;
+import javax.net.ssl.HandshakeCompletedListener;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLException;
import javax.net.ssl.SSLHandshakeException;
+import javax.net.ssl.SSLParameters;
import javax.net.ssl.SSLSession;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
-import libcore.java.security.StandardNames;
import libcore.java.security.TestKeyStore;
import libcore.java.util.AbstractResourceLeakageDetectorTestCase;
import libcore.javax.net.ssl.TestSSLContext;
@@ -84,7 +88,7 @@ import static com.google.mockwebserver.SocketPolicy.SHUTDOWN_OUTPUT_AT_END;
public final class URLConnectionTest extends AbstractResourceLeakageDetectorTestCase {
private MockWebServer server;
- private HttpResponseCache cache;
+ private AndroidShimResponseCache cache;
private String hostName;
@Override protected void setUp() throws Exception {
@@ -674,11 +678,144 @@ public final class URLConnectionTest extends AbstractResourceLeakageDetectorTest
private void initResponseCache() throws IOException {
String tmp = System.getProperty("java.io.tmpdir");
File cacheDir = new File(tmp, "HttpCache-" + UUID.randomUUID());
- cache = new HttpResponseCache(cacheDir, Integer.MAX_VALUE);
+ cache = AndroidShimResponseCache.create(cacheDir, Integer.MAX_VALUE);
ResponseCache.setDefault(cache);
}
/**
+ * Test Etag headers are returned correctly when a client-side cache is not installed.
+ * https://code.google.com/p/android/issues/detail?id=108949
+ */
+ public void testEtagHeaders_uncached() throws Exception {
+ final String etagValue1 = "686897696a7c876b7e";
+ final String body1 = "Response with etag 1";
+ final String etagValue2 = "686897696a7c876b7f";
+ final String body2 = "Response with etag 2";
+
+ server.enqueue(
+ new MockResponse()
+ .setBody(body1)
+ .setHeader("Content-Type", "text/plain")
+ .setHeader("Etag", etagValue1));
+ server.enqueue(
+ new MockResponse()
+ .setBody(body2)
+ .setHeader("Content-Type", "text/plain")
+ .setHeader("Etag", etagValue2));
+ server.play();
+
+ URL url = server.getUrl("/");
+ HttpURLConnection connection1 = (HttpURLConnection) url.openConnection();
+ assertEquals(etagValue1, connection1.getHeaderField("Etag"));
+ assertContent(body1, connection1);
+ connection1.disconnect();
+
+ // Discard the server-side record of the request made.
+ server.takeRequest();
+
+ HttpURLConnection connection2 = (HttpURLConnection) url.openConnection();
+ assertEquals(etagValue2, connection2.getHeaderField("Etag"));
+ assertContent(body2, connection2);
+ connection2.disconnect();
+
+ // Check the client did not cache.
+ RecordedRequest request = server.takeRequest();
+ assertNull(request.getHeader("If-None-Match"));
+ }
+
+ /**
+ * Test Etag headers are returned correctly when a client-side cache is installed and the server
+ * data is unchanged.
+ * https://code.google.com/p/android/issues/detail?id=108949
+ */
+ public void testEtagHeaders_cachedWithServerHit() throws Exception {
+ final String etagValue = "686897696a7c876b7e";
+ final String body = "Response with etag";
+
+ server.enqueue(
+ new MockResponse()
+ .setBody(body)
+ .setResponseCode(HttpURLConnection.HTTP_OK)
+ .setHeader("Content-Type", "text/plain")
+ .setHeader("Etag", etagValue));
+
+ server.enqueue(
+ new MockResponse()
+ .setResponseCode(HttpURLConnection.HTTP_NOT_MODIFIED));
+ server.play();
+
+ initResponseCache();
+
+ URL url = server.getUrl("/");
+ HttpURLConnection connection = (HttpURLConnection) url.openConnection();
+ assertEquals(etagValue, connection.getHeaderField("Etag"));
+ assertContent(body, connection);
+ connection.disconnect();
+
+ // Discard the server-side record of the request made.
+ server.takeRequest();
+
+ // Confirm the cached body is returned along with the original etag header.
+ HttpURLConnection cachedConnection = (HttpURLConnection) url.openConnection();
+ assertEquals(etagValue, cachedConnection.getHeaderField("Etag"));
+ assertContent(body, cachedConnection);
+ cachedConnection.disconnect();
+
+ // Check the client formatted the request correctly.
+ RecordedRequest request = server.takeRequest();
+ assertEquals(etagValue, request.getHeader("If-None-Match"));
+ }
+
+ /**
+ * Test Etag headers are returned correctly when a client-side cache is installed and the server
+ * data has changed.
+ * https://code.google.com/p/android/issues/detail?id=108949
+ */
+ public void testEtagHeaders_cachedWithServerMiss() throws Exception {
+ final String etagValue1 = "686897696a7c876b7e";
+ final String body1 = "Response with etag 1";
+ final String etagValue2 = "686897696a7c876b7f";
+ final String body2 = "Response with etag 2";
+
+ server.enqueue(
+ new MockResponse()
+ .setBody(body1)
+ .setResponseCode(HttpURLConnection.HTTP_OK)
+ .setHeader("Content-Type", "text/plain")
+ .setHeader("Etag", etagValue1));
+
+ server.enqueue(
+ new MockResponse()
+ .setBody(body2)
+ .setResponseCode(HttpURLConnection.HTTP_OK)
+ .setHeader("Content-Type", "text/plain")
+ .setHeader("Etag", etagValue2));
+
+ server.play();
+
+ initResponseCache();
+
+ URL url = server.getUrl("/");
+ HttpURLConnection connection = (HttpURLConnection) url.openConnection();
+ assertEquals(etagValue1, connection.getHeaderField("Etag"));
+ assertContent(body1, connection);
+ connection.disconnect();
+
+ // Discard the server-side record of the request made.
+ server.takeRequest();
+
+ // Confirm the new body is returned along with the new etag header.
+ HttpURLConnection cachedConnection = (HttpURLConnection) url.openConnection();
+ assertEquals(etagValue2, cachedConnection.getHeaderField("Etag"));
+ assertContent(body2, cachedConnection);
+ cachedConnection.disconnect();
+
+ // Check the client formatted the request correctly.
+ RecordedRequest request = server.takeRequest();
+ assertEquals(etagValue1, request.getHeader("If-None-Match"));
+ }
+
+ /**
* Test which headers are sent unencrypted to the HTTP proxy.
*/
public void testProxyConnectIncludesProxyHeadersOnly()
@@ -2074,6 +2211,19 @@ public final class URLConnectionTest extends AbstractResourceLeakageDetectorTest
connection.disconnect();
}
+ public void testLastModified() throws Exception {
+ server.enqueue(new MockResponse()
+ .addHeader("Last-Modified", "Wed, 27 Nov 2013 11:26:00 GMT")
+ .setBody("Hello"));
+ server.play();
+
+ HttpURLConnection connection = (HttpURLConnection) server.getUrl("/").openConnection();
+ connection.connect();
+
+ assertEquals(1385551560000L, connection.getLastModified());
+ assertEquals(1385551560000L, connection.getHeaderFieldDate("Last-Modified", -1));
+ }
+
public void testClientSendsContentLength() throws Exception {
server.enqueue(new MockResponse().setBody("A"));
server.play();
@@ -2185,52 +2335,107 @@ public final class URLConnectionTest extends AbstractResourceLeakageDetectorTest
urlConnection.getInputStream();
}
- public void testSslFallback() throws Exception {
+ public void testSslFallback_allSupportedProtocols() throws Exception {
TestSSLContext testSSLContext = TestSSLContext.create();
- // This server socket factory only supports SSLv3. This is to avoid issues due to SCSV
- // checks. See https://tools.ietf.org/html/draft-ietf-tls-downgrade-scsv-00
+ String[] allSupportedProtocols = { "TLSv1.2", "TLSv1.1", "TLSv1", "SSLv3" };
SSLSocketFactory serverSocketFactory =
new LimitedProtocolsSocketFactory(
testSSLContext.serverContext.getSocketFactory(),
- "SSLv3");
-
+ allSupportedProtocols);
server.useHttps(serverSocketFactory, false);
server.enqueue(new MockResponse().setSocketPolicy(FAIL_HANDSHAKE));
- server.enqueue(new MockResponse().setBody("This required a 2nd handshake"));
+ server.enqueue(new MockResponse().setSocketPolicy(FAIL_HANDSHAKE));
+ server.enqueue(new MockResponse().setSocketPolicy(FAIL_HANDSHAKE));
+ server.enqueue(new MockResponse().setBody("This required fallbacks"));
server.play();
HttpsURLConnection connection = (HttpsURLConnection) server.getUrl("/").openConnection();
- // Keep track of the client sockets created so that we can interrogate them.
- RecordingSocketFactory clientSocketFactory =
- new RecordingSocketFactory(testSSLContext.clientContext.getSocketFactory());
+ // Keeps track of the client sockets created so that we can interrogate them.
+ final boolean disableFallbackScsv = true;
+ FallbackTestClientSocketFactory clientSocketFactory = new FallbackTestClientSocketFactory(
+ new LimitedProtocolsSocketFactory(
+ testSSLContext.clientContext.getSocketFactory(), allSupportedProtocols),
+ disableFallbackScsv);
connection.setSSLSocketFactory(clientSocketFactory);
- assertEquals("This required a 2nd handshake",
+ assertEquals("This required fallbacks",
readAscii(connection.getInputStream(), Integer.MAX_VALUE));
+ // Confirm the server accepted a single connection.
RecordedRequest retry = server.takeRequest();
assertEquals(0, retry.getSequenceNumber());
assertEquals("SSLv3", retry.getSslProtocol());
// Confirm the client fallback looks ok.
List<SSLSocket> createdSockets = clientSocketFactory.getCreatedSockets();
- assertEquals(2, createdSockets.size());
- SSLSocket clientSocket1 = createdSockets.get(0);
- List<String> clientSocket1EnabledProtocols = Arrays.asList(
- clientSocket1.getEnabledProtocols());
- assertContains(clientSocket1EnabledProtocols, "TLSv1.2");
- List<String> clientSocket1EnabledCiphers =
- Arrays.asList(clientSocket1.getEnabledCipherSuites());
- assertContainsNoneMatching(
- clientSocket1EnabledCiphers, StandardNames.CIPHER_SUITE_FALLBACK);
-
- SSLSocket clientSocket2 = createdSockets.get(1);
- List<String> clientSocket2EnabledProtocols =
- Arrays.asList(clientSocket2.getEnabledProtocols());
- assertContainsNoneMatching(clientSocket2EnabledProtocols, "TLSv1.2");
- List<String> clientSocket2EnabledCiphers =
- Arrays.asList(clientSocket2.getEnabledCipherSuites());
- assertContains(clientSocket2EnabledCiphers, StandardNames.CIPHER_SUITE_FALLBACK);
+ assertEquals(4, createdSockets.size());
+ TlsFallbackDisabledScsvSSLSocket clientSocket1 =
+ (TlsFallbackDisabledScsvSSLSocket) createdSockets.get(0);
+ assertSslSocket(clientSocket1,
+ false /* expectedWasFallbackScsvSet */, "TLSv1.2", "TLSv1.1", "TLSv1", "SSLv3");
+
+ TlsFallbackDisabledScsvSSLSocket clientSocket2 =
+ (TlsFallbackDisabledScsvSSLSocket) createdSockets.get(1);
+ assertSslSocket(clientSocket2,
+ true /* expectedWasFallbackScsvSet */, "TLSv1.1", "TLSv1", "SSLv3");
+
+ TlsFallbackDisabledScsvSSLSocket clientSocket3 =
+ (TlsFallbackDisabledScsvSSLSocket) createdSockets.get(2);
+ assertSslSocket(clientSocket3, true /* expectedWasFallbackScsvSet */, "TLSv1", "SSLv3");
+
+ TlsFallbackDisabledScsvSSLSocket clientSocket4 =
+ (TlsFallbackDisabledScsvSSLSocket) createdSockets.get(3);
+ assertSslSocket(clientSocket4, true /* expectedWasFallbackScsvSet */, "SSLv3");
+ }
+
+ public void testSslFallback_defaultProtocols() throws Exception {
+ TestSSLContext testSSLContext = TestSSLContext.create();
+
+ server.useHttps(testSSLContext.serverContext.getSocketFactory(), false);
+ server.enqueue(new MockResponse().setSocketPolicy(FAIL_HANDSHAKE));
+ server.enqueue(new MockResponse().setSocketPolicy(FAIL_HANDSHAKE));
+ server.enqueue(new MockResponse().setBody("This required fallbacks"));
+ server.play();
+
+ HttpsURLConnection connection = (HttpsURLConnection) server.getUrl("/").openConnection();
+ // Keeps track of the client sockets created so that we can interrogate them.
+ final boolean disableFallbackScsv = true;
+ FallbackTestClientSocketFactory clientSocketFactory = new FallbackTestClientSocketFactory(
+ testSSLContext.clientContext.getSocketFactory(),
+ disableFallbackScsv);
+ connection.setSSLSocketFactory(clientSocketFactory);
+ assertEquals("This required fallbacks",
+ readAscii(connection.getInputStream(), Integer.MAX_VALUE));
+
+ // Confirm the server accepted a single connection.
+ RecordedRequest retry = server.takeRequest();
+ assertEquals(0, retry.getSequenceNumber());
+ assertEquals("TLSv1", retry.getSslProtocol());
+
+ // Confirm the client fallback looks ok.
+ List<SSLSocket> createdSockets = clientSocketFactory.getCreatedSockets();
+ assertEquals(3, createdSockets.size());
+ TlsFallbackDisabledScsvSSLSocket clientSocket1 =
+ (TlsFallbackDisabledScsvSSLSocket) createdSockets.get(0);
+ assertSslSocket(clientSocket1,
+ false /* expectedWasFallbackScsvSet */, "TLSv1.2", "TLSv1.1", "TLSv1");
+
+ TlsFallbackDisabledScsvSSLSocket clientSocket2 =
+ (TlsFallbackDisabledScsvSSLSocket) createdSockets.get(1);
+ assertSslSocket(clientSocket2, true /* expectedWasFallbackScsvSet */, "TLSv1.1", "TLSv1");
+
+ TlsFallbackDisabledScsvSSLSocket clientSocket3 =
+ (TlsFallbackDisabledScsvSSLSocket) createdSockets.get(2);
+ assertSslSocket(clientSocket3, true /* expectedWasFallbackScsvSet */, "TLSv1");
+ }
+
+ private static void assertSslSocket(TlsFallbackDisabledScsvSSLSocket socket,
+ boolean expectedWasFallbackScsvSet, String... expectedEnabledProtocols) {
+ Set<String> enabledProtocols =
+ new HashSet<String>(Arrays.asList(socket.getEnabledProtocols()));
+ Set<String> expectedProtocolsSet = new HashSet<String>(Arrays.asList(expectedEnabledProtocols));
+ assertEquals(expectedProtocolsSet, enabledProtocols);
+ assertEquals(expectedWasFallbackScsvSet, socket.wasTlsFallbackScsvSet());
}
public void testInspectSslBeforeConnect() throws Exception {
@@ -2491,36 +2696,37 @@ public final class URLConnectionTest extends AbstractResourceLeakageDetectorTest
}
@Override
- public Socket createSocket(Socket s, String host, int port, boolean autoClose)
+ public SSLSocket createSocket(Socket s, String host, int port, boolean autoClose)
throws IOException {
- return delegate.createSocket(s, host, port, autoClose);
+ return (SSLSocket) delegate.createSocket(s, host, port, autoClose);
}
@Override
- public Socket createSocket() throws IOException {
- return delegate.createSocket();
+ public SSLSocket createSocket() throws IOException {
+ return (SSLSocket) delegate.createSocket();
}
@Override
- public Socket createSocket(String host, int port) throws IOException, UnknownHostException {
- return delegate.createSocket(host, port);
+ public SSLSocket createSocket(String host, int port)
+ throws IOException, UnknownHostException {
+ return (SSLSocket) delegate.createSocket(host, port);
}
@Override
- public Socket createSocket(String host, int port, InetAddress localHost,
+ public SSLSocket createSocket(String host, int port, InetAddress localHost,
int localPort) throws IOException, UnknownHostException {
- return delegate.createSocket(host, port, localHost, localPort);
+ return (SSLSocket) delegate.createSocket(host, port, localHost, localPort);
}
@Override
- public Socket createSocket(InetAddress host, int port) throws IOException {
- return delegate.createSocket(host, port);
+ public SSLSocket createSocket(InetAddress host, int port) throws IOException {
+ return (SSLSocket) delegate.createSocket(host, port);
}
@Override
- public Socket createSocket(InetAddress address, int port,
+ public SSLSocket createSocket(InetAddress address, int port,
InetAddress localAddress, int localPort) throws IOException {
- return delegate.createSocket(address, port, localAddress, localPort);
+ return (SSLSocket) delegate.createSocket(address, port, localAddress, localPort);
}
}
@@ -2539,7 +2745,7 @@ public final class URLConnectionTest extends AbstractResourceLeakageDetectorTest
}
@Override
- public Socket createSocket(Socket s, String host, int port, boolean autoClose)
+ public SSLSocket createSocket(Socket s, String host, int port, boolean autoClose)
throws IOException {
SSLSocket socket = (SSLSocket) delegate.createSocket(s, host, port, autoClose);
socket.setEnabledProtocols(protocols);
@@ -2547,21 +2753,22 @@ public final class URLConnectionTest extends AbstractResourceLeakageDetectorTest
}
@Override
- public Socket createSocket() throws IOException {
+ public SSLSocket createSocket() throws IOException {
SSLSocket socket = (SSLSocket) delegate.createSocket();
socket.setEnabledProtocols(protocols);
return socket;
}
@Override
- public Socket createSocket(String host, int port) throws IOException, UnknownHostException {
+ public SSLSocket createSocket(String host, int port)
+ throws IOException, UnknownHostException {
SSLSocket socket = (SSLSocket) delegate.createSocket(host, port);
socket.setEnabledProtocols(protocols);
return socket;
}
@Override
- public Socket createSocket(String host, int port, InetAddress localHost,
+ public SSLSocket createSocket(String host, int port, InetAddress localHost,
int localPort) throws IOException, UnknownHostException {
SSLSocket socket = (SSLSocket) delegate.createSocket(host, port, localHost, localPort);
socket.setEnabledProtocols(protocols);
@@ -2569,14 +2776,14 @@ public final class URLConnectionTest extends AbstractResourceLeakageDetectorTest
}
@Override
- public Socket createSocket(InetAddress host, int port) throws IOException {
+ public SSLSocket createSocket(InetAddress host, int port) throws IOException {
SSLSocket socket = (SSLSocket) delegate.createSocket(host, port);
socket.setEnabledProtocols(protocols);
return socket;
}
@Override
- public Socket createSocket(InetAddress address, int port,
+ public SSLSocket createSocket(InetAddress address, int port,
InetAddress localAddress, int localPort) throws IOException {
SSLSocket socket =
(SSLSocket) delegate.createSocket(address, port, localAddress, localPort);
@@ -2586,58 +2793,337 @@ public final class URLConnectionTest extends AbstractResourceLeakageDetectorTest
}
/**
- * An SSLSocketFactory that delegates calls and keeps a record of any sockets created.
+ * An {@link javax.net.ssl.SSLSocket} that delegates all calls.
*/
- private static class RecordingSocketFactory extends DelegatingSSLSocketFactory {
+ private static abstract class DelegatingSSLSocket extends SSLSocket {
+ protected final SSLSocket delegate;
+
+ public DelegatingSSLSocket(SSLSocket delegate) {
+ this.delegate = delegate;
+ }
+
+ @Override public void shutdownInput() throws IOException {
+ delegate.shutdownInput();
+ }
+
+ @Override public void shutdownOutput() throws IOException {
+ delegate.shutdownOutput();
+ }
+
+ @Override public String[] getSupportedCipherSuites() {
+ return delegate.getSupportedCipherSuites();
+ }
+
+ @Override public String[] getEnabledCipherSuites() {
+ return delegate.getEnabledCipherSuites();
+ }
+
+ @Override public void setEnabledCipherSuites(String[] suites) {
+ delegate.setEnabledCipherSuites(suites);
+ }
+
+ @Override public String[] getSupportedProtocols() {
+ return delegate.getSupportedProtocols();
+ }
+
+ @Override public String[] getEnabledProtocols() {
+ return delegate.getEnabledProtocols();
+ }
+
+ @Override public void setEnabledProtocols(String[] protocols) {
+ delegate.setEnabledProtocols(protocols);
+ }
+
+ @Override public SSLSession getSession() {
+ return delegate.getSession();
+ }
+
+ @Override public void addHandshakeCompletedListener(HandshakeCompletedListener listener) {
+ delegate.addHandshakeCompletedListener(listener);
+ }
+
+ @Override public void removeHandshakeCompletedListener(HandshakeCompletedListener listener) {
+ delegate.removeHandshakeCompletedListener(listener);
+ }
+
+ @Override public void startHandshake() throws IOException {
+ delegate.startHandshake();
+ }
+
+ @Override public void setUseClientMode(boolean mode) {
+ delegate.setUseClientMode(mode);
+ }
+
+ @Override public boolean getUseClientMode() {
+ return delegate.getUseClientMode();
+ }
+
+ @Override public void setNeedClientAuth(boolean need) {
+ delegate.setNeedClientAuth(need);
+ }
+
+ @Override public void setWantClientAuth(boolean want) {
+ delegate.setWantClientAuth(want);
+ }
+
+ @Override public boolean getNeedClientAuth() {
+ return delegate.getNeedClientAuth();
+ }
+
+ @Override public boolean getWantClientAuth() {
+ return delegate.getWantClientAuth();
+ }
+ @Override public void setEnableSessionCreation(boolean flag) {
+ delegate.setEnableSessionCreation(flag);
+ }
+
+ @Override public boolean getEnableSessionCreation() {
+ return delegate.getEnableSessionCreation();
+ }
+
+ @Override public SSLParameters getSSLParameters() {
+ return delegate.getSSLParameters();
+ }
+
+ @Override public void setSSLParameters(SSLParameters p) {
+ delegate.setSSLParameters(p);
+ }
+
+ @Override public void close() throws IOException {
+ delegate.close();
+ }
+
+ @Override public InetAddress getInetAddress() {
+ return delegate.getInetAddress();
+ }
+
+ @Override public InputStream getInputStream() throws IOException {
+ return delegate.getInputStream();
+ }
+
+ @Override public boolean getKeepAlive() throws SocketException {
+ return delegate.getKeepAlive();
+ }
+
+ @Override public InetAddress getLocalAddress() {
+ return delegate.getLocalAddress();
+ }
+
+ @Override public int getLocalPort() {
+ return delegate.getLocalPort();
+ }
+
+ @Override public OutputStream getOutputStream() throws IOException {
+ return delegate.getOutputStream();
+ }
+
+ @Override public int getPort() {
+ return delegate.getPort();
+ }
+
+ @Override public int getSoLinger() throws SocketException {
+ return delegate.getSoLinger();
+ }
+
+ @Override public int getReceiveBufferSize() throws SocketException {
+ return delegate.getReceiveBufferSize();
+ }
+
+ @Override public int getSendBufferSize() throws SocketException {
+ return delegate.getSendBufferSize();
+ }
+
+ @Override public int getSoTimeout() throws SocketException {
+ return delegate.getSoTimeout();
+ }
+
+ @Override public boolean getTcpNoDelay() throws SocketException {
+ return delegate.getTcpNoDelay();
+ }
+
+ @Override public void setKeepAlive(boolean keepAlive) throws SocketException {
+ delegate.setKeepAlive(keepAlive);
+ }
+
+ @Override public void setSendBufferSize(int size) throws SocketException {
+ delegate.setSendBufferSize(size);
+ }
+
+ @Override public void setReceiveBufferSize(int size) throws SocketException {
+ delegate.setReceiveBufferSize(size);
+ }
+
+ @Override public void setSoLinger(boolean on, int timeout) throws SocketException {
+ delegate.setSoLinger(on, timeout);
+ }
+
+ @Override public void setSoTimeout(int timeout) throws SocketException {
+ delegate.setSoTimeout(timeout);
+ }
+
+ @Override public void setTcpNoDelay(boolean on) throws SocketException {
+ delegate.setTcpNoDelay(on);
+ }
+
+ @Override public String toString() {
+ return delegate.toString();
+ }
+
+ @Override public SocketAddress getLocalSocketAddress() {
+ return delegate.getLocalSocketAddress();
+ }
+
+ @Override public SocketAddress getRemoteSocketAddress() {
+ return delegate.getRemoteSocketAddress();
+ }
+
+ @Override public boolean isBound() {
+ return delegate.isBound();
+ }
+
+ @Override public boolean isConnected() {
+ return delegate.isConnected();
+ }
+
+ @Override public boolean isClosed() {
+ return delegate.isClosed();
+ }
+
+ @Override public void bind(SocketAddress localAddr) throws IOException {
+ delegate.bind(localAddr);
+ }
+
+ @Override public void connect(SocketAddress remoteAddr) throws IOException {
+ delegate.connect(remoteAddr);
+ }
+
+ @Override public void connect(SocketAddress remoteAddr, int timeout) throws IOException {
+ delegate.connect(remoteAddr, timeout);
+ }
+
+ @Override public boolean isInputShutdown() {
+ return delegate.isInputShutdown();
+ }
+
+ @Override public boolean isOutputShutdown() {
+ return delegate.isOutputShutdown();
+ }
+
+ @Override public void setReuseAddress(boolean reuse) throws SocketException {
+ delegate.setReuseAddress(reuse);
+ }
+
+ @Override public boolean getReuseAddress() throws SocketException {
+ return delegate.getReuseAddress();
+ }
+
+ @Override public void setOOBInline(boolean oobinline) throws SocketException {
+ delegate.setOOBInline(oobinline);
+ }
+
+ @Override public boolean getOOBInline() throws SocketException {
+ return delegate.getOOBInline();
+ }
+
+ @Override public void setTrafficClass(int value) throws SocketException {
+ delegate.setTrafficClass(value);
+ }
+
+ @Override public int getTrafficClass() throws SocketException {
+ return delegate.getTrafficClass();
+ }
+
+ @Override public void sendUrgentData(int value) throws IOException {
+ delegate.sendUrgentData(value);
+ }
+
+ @Override public SocketChannel getChannel() {
+ return delegate.getChannel();
+ }
+
+ @Override public void setPerformancePreferences(int connectionTime, int latency,
+ int bandwidth) {
+ delegate.setPerformancePreferences(connectionTime, latency, bandwidth);
+ }
+ }
+
+ /**
+ * An SSLSocketFactory that delegates calls. It keeps a record of any sockets created.
+ * If {@link #disableTlsFallbackScsv} is set to {@code true} then sockets created by the
+ * delegate are wrapped with ones that will not accept the {@link #TLS_FALLBACK_SCSV} cipher,
+ * thus bypassing server-side fallback checks on platforms that support it. Unfortunately this
+ * wrapping will disable any reflection-based calls to SSLSocket from Platform.
+ */
+ private static class FallbackTestClientSocketFactory extends DelegatingSSLSocketFactory {
+ /**
+ * The cipher suite used during TLS connection fallback to indicate a fallback.
+ * See https://tools.ietf.org/html/draft-ietf-tls-downgrade-scsv-00
+ */
+ public static final String TLS_FALLBACK_SCSV = "TLS_FALLBACK_SCSV";
+
+ private final boolean disableTlsFallbackScsv;
private final List<SSLSocket> createdSockets = new ArrayList<SSLSocket>();
- private RecordingSocketFactory(SSLSocketFactory delegate) {
+ public FallbackTestClientSocketFactory(SSLSocketFactory delegate,
+ boolean disableTlsFallbackScsv) {
super(delegate);
+ this.disableTlsFallbackScsv = disableTlsFallbackScsv;
}
- @Override
- public Socket createSocket(Socket s, String host, int port, boolean autoClose)
+ @Override public SSLSocket createSocket(Socket s, String host, int port, boolean autoClose)
throws IOException {
- SSLSocket socket = (SSLSocket) delegate.createSocket(s, host, port, autoClose);
+ SSLSocket socket = super.createSocket(s, host, port, autoClose);
+ if (disableTlsFallbackScsv) {
+ socket = new TlsFallbackDisabledScsvSSLSocket(socket);
+ }
createdSockets.add(socket);
return socket;
}
- @Override
- public Socket createSocket() throws IOException {
- SSLSocket socket = (SSLSocket) delegate.createSocket();
+ @Override public SSLSocket createSocket() throws IOException {
+ SSLSocket socket = super.createSocket();
+ if (disableTlsFallbackScsv) {
+ socket = new TlsFallbackDisabledScsvSSLSocket(socket);
+ }
createdSockets.add(socket);
return socket;
}
- @Override
- public Socket createSocket(String host, int port) throws IOException, UnknownHostException {
- SSLSocket socket = (SSLSocket) delegate.createSocket(host, port);
+ @Override public SSLSocket createSocket(String host,int port) throws IOException {
+ SSLSocket socket = super.createSocket(host, port);
+ if (disableTlsFallbackScsv) {
+ socket = new TlsFallbackDisabledScsvSSLSocket(socket);
+ }
createdSockets.add(socket);
return socket;
}
- @Override
- public Socket createSocket(String host, int port, InetAddress localHost,
- int localPort) throws IOException, UnknownHostException {
- SSLSocket socket = (SSLSocket) delegate.createSocket(host, port, localHost, localPort);
+ @Override public SSLSocket createSocket(String host,int port, InetAddress localHost,
+ int localPort) throws IOException {
+ SSLSocket socket = super.createSocket(host, port, localHost, localPort);
+ if (disableTlsFallbackScsv) {
+ socket = new TlsFallbackDisabledScsvSSLSocket(socket);
+ }
createdSockets.add(socket);
return socket;
}
- @Override
- public Socket createSocket(InetAddress host, int port) throws IOException {
- SSLSocket socket = (SSLSocket) delegate.createSocket(host, port);
+ @Override public SSLSocket createSocket(InetAddress host,int port) throws IOException {
+ SSLSocket socket = super.createSocket(host, port);
+ if (disableTlsFallbackScsv) {
+ socket = new TlsFallbackDisabledScsvSSLSocket(socket);
+ }
createdSockets.add(socket);
return socket;
}
- @Override
- public Socket createSocket(InetAddress address, int port,
+ @Override public SSLSocket createSocket(InetAddress address,int port,
InetAddress localAddress, int localPort) throws IOException {
- SSLSocket socket =
- (SSLSocket) delegate.createSocket(address, port, localAddress, localPort);
+ SSLSocket socket = super.createSocket(address, port, localAddress, localPort);
+ if (disableTlsFallbackScsv) {
+ socket = new TlsFallbackDisabledScsvSSLSocket(socket);
+ }
createdSockets.add(socket);
return socket;
}
@@ -2647,4 +3133,31 @@ public final class URLConnectionTest extends AbstractResourceLeakageDetectorTest
}
}
+ private static class TlsFallbackDisabledScsvSSLSocket extends DelegatingSSLSocket {
+
+ private boolean tlsFallbackScsvSet;
+
+ public TlsFallbackDisabledScsvSSLSocket(SSLSocket socket) {
+ super(socket);
+ }
+
+ @Override public void setEnabledCipherSuites(String[] suites) {
+ List<String> enabledCipherSuites = new ArrayList<String>(suites.length);
+ for (String suite : suites) {
+ if (suite.equals(FallbackTestClientSocketFactory.TLS_FALLBACK_SCSV)) {
+ // Record that an attempt was made to set TLS_FALLBACK_SCSV, but don't actually
+ // set it.
+ tlsFallbackScsvSet = true;
+ } else {
+ enabledCipherSuites.add(suite);
+ }
+ }
+ delegate.setEnabledCipherSuites(
+ enabledCipherSuites.toArray(new String[enabledCipherSuites.size()]));
+ }
+
+ public boolean wasTlsFallbackScsvSet() {
+ return tlsFallbackScsvSet;
+ }
+ }
}
diff --git a/luni/src/test/java/libcore/java/nio/channels/SelectorTest.java b/luni/src/test/java/libcore/java/nio/channels/SelectorTest.java
index 9789197..41b434d 100644
--- a/luni/src/test/java/libcore/java/nio/channels/SelectorTest.java
+++ b/luni/src/test/java/libcore/java/nio/channels/SelectorTest.java
@@ -15,7 +15,6 @@
*/
package libcore.java.nio.channels;
-import android.system.OsConstants;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
@@ -28,7 +27,6 @@ import java.nio.channels.SocketChannel;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import junit.framework.TestCase;
-import libcore.io.Libcore;
import tests.net.StuckServer;
public class SelectorTest extends TestCase {
@@ -71,25 +69,6 @@ public class SelectorTest extends TestCase {
}
}
- // http://b/6453247
- // This test won't work on the host until/unless we start using libcorkscrew there.
- // The runtime itself blocks SIGQUIT, so that doesn't cause poll(2) to EINTR directly.
- // The EINTR is caused by the way libcorkscrew works.
- public void testEINTR() throws Exception {
- Selector selector = Selector.open();
- new Thread(new Runnable() {
- @Override public void run() {
- try {
- Thread.sleep(2000);
- Libcore.os.kill(Libcore.os.getpid(), OsConstants.SIGQUIT);
- } catch (Exception ex) {
- fail();
- }
- }
- }).start();
- assertEquals(0, selector.select());
- }
-
// http://code.google.com/p/android/issues/detail?id=15388
public void testInterrupted() throws IOException {
Selector selector = Selector.open();
diff --git a/luni/src/test/java/libcore/java/nio/charset/CharsetEncoderTest.java b/luni/src/test/java/libcore/java/nio/charset/CharsetEncoderTest.java
index ff510e0..e9ab8ae 100644
--- a/luni/src/test/java/libcore/java/nio/charset/CharsetEncoderTest.java
+++ b/luni/src/test/java/libcore/java/nio/charset/CharsetEncoderTest.java
@@ -20,8 +20,10 @@ import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.charset.Charset;
import java.nio.charset.CharsetEncoder;
+import java.nio.charset.CharsetDecoder;
import java.nio.charset.CoderResult;
import java.nio.charset.CodingErrorAction;
+import java.nio.charset.StandardCharsets;
import java.util.Arrays;
public class CharsetEncoderTest extends junit.framework.TestCase {
@@ -161,4 +163,71 @@ public class CharsetEncoderTest extends junit.framework.TestCase {
assertEquals(CoderResult.UNDERFLOW, cr);
assertEquals(8, bb.position());
}
+
+ // Discards all input. Outputs a single byte 'X' on flush.
+ private static final class MockCharset extends Charset {
+ static final Charset INSTANCE = new MockCharset();
+
+ private MockCharset() {
+ super("MockCharset", new String[0]);
+ }
+
+ public boolean contains(Charset charset) {
+ return false;
+ }
+
+ public CharsetEncoder newEncoder() {
+ return new CharsetEncoder(INSTANCE, 1.f, 1.f) {
+ protected CoderResult encodeLoop(CharBuffer in, ByteBuffer out) {
+ in.position(in.limit());
+ return CoderResult.UNDERFLOW;
+ }
+
+ protected CoderResult implFlush(ByteBuffer out) {
+ out.put((byte) 'X');
+ return CoderResult.UNDERFLOW;
+ }
+ };
+ }
+
+ public CharsetDecoder newDecoder() {
+ return new CharsetDecoder(INSTANCE, 1.f, 1.f) {
+ protected CoderResult decodeLoop(ByteBuffer in, CharBuffer out) {
+ in.position(in.limit());
+ return CoderResult.UNDERFLOW;
+ }
+ };
+ }
+ }
+
+ // Repeated calls to flush() should not result in repeated calls to implFlush().
+ public void testFlushNotCallingImplFlushRepeatedly() {
+ CharsetEncoder e = MockCharset.INSTANCE.newEncoder();
+ ByteBuffer bb = ByteBuffer.allocate(4);
+ CoderResult cr = e.encode(CharBuffer.allocate(0), bb, true);
+ assertEquals(CoderResult.UNDERFLOW, cr);
+ cr = e.flush(bb);
+ assertEquals(CoderResult.UNDERFLOW, cr);
+ cr = e.flush(bb);
+ assertEquals(CoderResult.UNDERFLOW, cr);
+ assertEquals(1, bb.position());
+ assertEquals((byte) 'X', bb.get(0));
+ assertEquals(0x00, bb.get(1));
+ assertEquals(0x00, bb.get(2));
+ assertEquals(0x00, bb.get(3));
+ }
+
+ // http://b/19185235
+ public void testFlushWithIncompleteInput() {
+ CharsetEncoder encoder = StandardCharsets.UTF_8.newEncoder();
+ ByteBuffer output = ByteBuffer.allocate(10);
+ CoderResult result = encoder.encode(CharBuffer.wrap("\ud800"), output,
+ true /* endOfInput */);
+ assertTrue(result.isUnderflow());
+
+ result = encoder.flush(output);
+ assertTrue(result.isMalformed());
+ assertEquals(1, result.length());
+ assertEquals(0, output.position());
+ }
}
diff --git a/luni/src/test/java/libcore/java/nio/charset/SettableCharsetProvider.java b/luni/src/test/java/libcore/java/nio/charset/SettableCharsetProvider.java
new file mode 100644
index 0000000..b4886d2
--- /dev/null
+++ b/luni/src/test/java/libcore/java/nio/charset/SettableCharsetProvider.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package libcore.java.nio.charset;
+
+import java.nio.charset.Charset;
+import java.nio.charset.spi.CharsetProvider;
+import java.util.Collections;
+import java.util.Iterator;
+
+/**
+ * This class is registered as a charset provider by the META-INF in the libcore
+ * tests jar. Since there isn't any convenient API to dynamically register and de-register
+ * charset-providers, this class allows tests to plug in a delegate that lives for the
+ * duration of the test.
+ */
+public final class SettableCharsetProvider extends CharsetProvider {
+ private static CharsetProvider delegate;
+
+ public static void setDelegate(CharsetProvider cp) {
+ delegate = cp;
+ }
+
+ public static void clearDelegate() {
+ delegate = null;
+ }
+
+ @Override
+ public Iterator<Charset> charsets() {
+ if (delegate != null) {
+ return delegate.charsets();
+ }
+
+ return Collections.emptyIterator();
+ }
+
+ @Override
+ public Charset charsetForName(String charsetName) {
+ if (delegate != null) {
+ return delegate.charsetForName(charsetName);
+ }
+
+ return null;
+ }
+}
diff --git a/luni/src/test/java/libcore/java/security/KeyPairGeneratorTest.java b/luni/src/test/java/libcore/java/security/KeyPairGeneratorTest.java
index e7fdb1f..10bb621 100644
--- a/luni/src/test/java/libcore/java/security/KeyPairGeneratorTest.java
+++ b/luni/src/test/java/libcore/java/security/KeyPairGeneratorTest.java
@@ -45,6 +45,7 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
+import java.util.Locale;
import java.util.Map;
import java.util.Set;
import javax.crypto.interfaces.DHPrivateKey;
@@ -55,13 +56,32 @@ import junit.framework.TestCase;
public class KeyPairGeneratorTest extends TestCase {
- public void test_providerCount() {
+ private List<Provider> providers = new ArrayList<Provider>();
+
+ @Override
+ public void setUp() {
Provider[] providers = Security.getProviders();
+ for (Provider p : providers) {
+ // Do not test AndroidKeyStore Provider. It does not accept vanilla public keys for
+ // signature verification. It's OKish not to test here because it's tested by
+ // cts/tests/tests/keystore.
+ if (!p.getName().startsWith("AndroidKeyStore")) {
+ this.providers.add(p);
+ }
+ }
+ }
+
+ @Override
+ public void tearDown() {
+ providers.clear();
+ }
+
+ public void test_providerCount() {
// We expect there to be at least one provider.
- assertTrue(providers.length > 0);
+ assertTrue(providers.size() > 0);
// If this fails remember to add _provider methods below. This test is sharded because it
// takes a long time to execute.
- assertTrue(providers.length < 10);
+ assertTrue(providers.size() < 10);
}
public void test_getInstance_provider0() throws Exception {
@@ -105,14 +125,14 @@ public class KeyPairGeneratorTest extends TestCase {
}
private void test_getInstance(int providerIndex) throws Exception {
- Provider[] providers = Security.getProviders();
- if (providerIndex >= providers.length) {
+ if (providerIndex >= providers.size()) {
// Providers can be added by vendors and other tests. We do not
// specify a fixed number and silenty pass if the provider at the
// specified index does not exist.
return;
}
- Provider provider = providers[providerIndex];
+
+ Provider provider = providers.get(providerIndex);
Set<Provider.Service> services = provider.getServices();
for (Provider.Service service : services) {
String type = service.getType();
@@ -120,12 +140,6 @@ public class KeyPairGeneratorTest extends TestCase {
continue;
}
String algorithm = service.getAlgorithm();
-
- // AndroidKeyStore is tested in CTS.
- if ("AndroidKeyStore".equals(provider.getName())) {
- continue;
- }
-
AlgorithmParameterSpec params = null;
if ("DH".equals(algorithm)) {
@@ -195,7 +209,6 @@ public class KeyPairGeneratorTest extends TestCase {
putKeySize("DiffieHellman", 512);
putKeySize("DiffieHellman", 512+64);
putKeySize("DiffieHellman", 1024);
- putKeySize("EC", 192);
putKeySize("EC", 224);
putKeySize("EC", 256);
putKeySize("EC", 384);
@@ -204,10 +217,10 @@ public class KeyPairGeneratorTest extends TestCase {
/** Elliptic Curve Crypto named curves that should be supported. */
private static final String[] EC_NAMED_CURVES = {
- // NIST P-192 aka SECG secp192r1 aka ANSI X9.62 prime192v1
- "secp192r1", "prime192v1",
// NIST P-256 aka SECG secp256r1 aka ANSI X9.62 prime256v1
"secp256r1", "prime256v1",
+ // NIST P-521 aka SECG secp521r1
+ "secp521r1",
};
private void test_KeyPairGenerator(KeyPairGenerator kpg) throws Exception {
@@ -264,7 +277,7 @@ public class KeyPairGeneratorTest extends TestCase {
}
private void test_Key(KeyPairGenerator kpg, Key k) throws Exception {
- String expectedAlgorithm = kpg.getAlgorithm().toUpperCase();
+ String expectedAlgorithm = kpg.getAlgorithm().toUpperCase(Locale.ROOT);
if (StandardNames.IS_RI && expectedAlgorithm.equals("DIFFIEHELLMAN")) {
expectedAlgorithm = "DH";
}
@@ -303,8 +316,6 @@ public class KeyPairGeneratorTest extends TestCase {
byte[] encoded = k.getEncoded();
String keyAlgo = k.getAlgorithm();
-
- Provider[] providers = Security.getProviders();
for (Provider p : providers) {
Set<Provider.Service> services = p.getServices();
for (Provider.Service service : services) {
diff --git a/luni/src/test/java/libcore/java/security/ProviderTest.java b/luni/src/test/java/libcore/java/security/ProviderTest.java
index 994214b..d3ccae1 100644
--- a/luni/src/test/java/libcore/java/security/ProviderTest.java
+++ b/luni/src/test/java/libcore/java/security/ProviderTest.java
@@ -41,6 +41,7 @@ import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
+import java.util.TreeMap;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.crypto.Cipher;
@@ -160,7 +161,7 @@ public class ProviderTest extends TestCase {
public void test_Provider_Properties() throws Exception {
/*
* A useful reference on Provider properties
- * <a href="http://java.sun.com/javase/6/docs/technotes/guides/security/crypto/HowToImplAProvider.html>
+ * <a href="http://java.sun.com/javase/6/docs/technotes/guides/security/crypto/HowToImplAProvider.html">
* How to Implement a Provider in the Java &trade; Cryptography Architecture
* </a>
*/
@@ -178,8 +179,8 @@ public class ProviderTest extends TestCase {
provider.get("Provider.id className"));
// build map of all known aliases and implementations
- Map<String,String> aliases = new HashMap<String,String>();
- Map<String,String> implementations = new HashMap<String,String>();
+ Map<String,String> aliases = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
+ Map<String,String> implementations = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
for (Entry<Object,Object> entry : provider.entrySet()) {
Object k = entry.getKey();
Object v = entry.getValue();
@@ -218,7 +219,8 @@ public class ProviderTest extends TestCase {
} catch (ClassNotFoundException e) {
// Sun forgot their own class
if (!className.equals("sun.security.pkcs11.P11MAC")) {
- fail("Could not find class " + className + " for " + typeAndAlgorithm);
+ fail("Could not find class " + className + " for " + typeAndAlgorithm
+ + " [provider=" + provider.getName() + "]");
}
}
}
@@ -227,8 +229,9 @@ public class ProviderTest extends TestCase {
for (Entry<String,String> entry : aliases.entrySet()) {
String alias = entry.getKey();
String actual = entry.getValue();
- assertTrue("Could not find implementation " + actual + " for alias " + alias,
- implementations.containsKey(actual));
+ assertTrue("Could not find implementation " + actual + " for alias " + alias +
+ " [provider=" + provider.getName() + "]",
+ implementations.containsKey(actual));
}
}
}
@@ -547,6 +550,15 @@ public class ProviderTest extends TestCase {
}
}
+ public void testProvider_removeProvider_Success() throws Exception {
+ MockProvider provider = new MockProvider("MockProvider");
+ assertNull(Security.getProvider(provider.getName()));
+ Security.addProvider(provider);
+ assertNotNull(Security.getProvider(provider.getName()));
+ Security.removeProvider(provider.getName());
+ assertNull(Security.getProvider(provider.getName()));
+ }
+
public static class MyCertStoreSpi extends CertStoreSpi {
public MyCertStoreSpi(CertStoreParameters params) throws InvalidAlgorithmParameterException {
super(params);
diff --git a/luni/src/test/java/libcore/java/security/SecureRandomTest.java b/luni/src/test/java/libcore/java/security/SecureRandomTest.java
index f9edbaa..e296775 100644
--- a/luni/src/test/java/libcore/java/security/SecureRandomTest.java
+++ b/luni/src/test/java/libcore/java/security/SecureRandomTest.java
@@ -102,6 +102,7 @@ public class SecureRandomTest extends TestCase {
public void testNewConstructors_Success() throws Exception {
SecureRandom sr1 = new SecureRandom();
+ assertNotNull(sr1.getProvider());
assertEquals(EXPECTED_PROVIDER, sr1.getProvider().getClass().getName());
test_SecureRandom(sr1);
diff --git a/luni/src/test/java/libcore/java/security/SignatureTest.java b/luni/src/test/java/libcore/java/security/SignatureTest.java
index 5e02f10..9aa75bd 100644
--- a/luni/src/test/java/libcore/java/security/SignatureTest.java
+++ b/luni/src/test/java/libcore/java/security/SignatureTest.java
@@ -31,6 +31,11 @@ import java.security.Signature;
import java.security.SignatureException;
import java.security.spec.DSAPrivateKeySpec;
import java.security.spec.DSAPublicKeySpec;
+import java.security.spec.ECFieldFp;
+import java.security.spec.ECParameterSpec;
+import java.security.spec.ECPoint;
+import java.security.spec.ECPublicKeySpec;
+import java.security.spec.EllipticCurve;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.RSAPrivateCrtKeySpec;
import java.security.spec.RSAPrivateKeySpec;
@@ -71,6 +76,49 @@ public class SignatureTest extends TestCase {
}
}
+ public void testSignature_getInstance_DoesNotSupportKeyClass_Success() throws Exception {
+ Provider mockProvider = new MockProvider("MockProvider") {
+ public void setup() {
+ put("Signature.FOO", MockSignatureSpi.AllKeyTypes.class.getName());
+ put("Signature.FOO SupportedKeyClasses", "None");
+ }
+ };
+
+ Security.addProvider(mockProvider);
+ try {
+ Signature s = Signature.getInstance("FOO", mockProvider);
+ s.initSign(new MockPrivateKey());
+ assertEquals(mockProvider, s.getProvider());
+ } finally {
+ Security.removeProvider(mockProvider.getName());
+ }
+ }
+
+ /**
+ * Several exceptions can be thrown by init. Check that in this case we throw the right one,
+ * as the error could fall under the umbrella of other exceptions.
+ * http://b/18987633
+ */
+ public void testSignature_init_DoesNotSupportKeyClass_throwsInvalidKeyException()
+ throws Exception {
+ Provider mockProvider = new MockProvider("MockProvider") {
+ public void setup() {
+ put("Signature.FOO", MockSignatureSpi.AllKeyTypes.class.getName());
+ put("Signature.FOO SupportedKeyClasses", "None");
+ }
+ };
+
+ Security.addProvider(mockProvider);
+ try {
+ Signature s = Signature.getInstance("FOO");
+ s.initSign(new MockPrivateKey());
+ fail("Expected InvalidKeyException");
+ } catch (InvalidKeyException expected) {
+ } finally {
+ Security.removeProvider(mockProvider.getName());
+ }
+ }
+
public void testSignature_getInstance_OnlyUsesSpecifiedProvider_SameNameAndClass_Success()
throws Exception {
Provider mockProvider = new MockProvider("MockProvider") {
@@ -238,6 +286,12 @@ public class SignatureTest extends TestCase {
public void test_getInstance() throws Exception {
Provider[] providers = Security.getProviders();
for (Provider provider : providers) {
+ // Do not test AndroidKeyStore's Signature. It needs an AndroidKeyStore-specific key.
+ // It's OKish not to test AndroidKeyStore's Signature here because it's tested
+ // by cts/tests/test/keystore.
+ if (provider.getName().startsWith("AndroidKeyStore")) {
+ continue;
+ }
Set<Provider.Service> services = provider.getServices();
for (Provider.Service service : services) {
String type = service.getType();
@@ -370,9 +424,14 @@ public class SignatureTest extends TestCase {
return data;
}
- // http://code.google.com/p/android/issues/detail?id=18566
- // http://b/5038554
- public void test18566() throws Exception {
+ /**
+ * This should actually fail because the ASN.1 encoding is incorrect. It is
+ * missing the NULL in the AlgorithmIdentifier field.
+ * <p>
+ * http://code.google.com/p/android/issues/detail?id=18566 <br/>
+ * http://b/5038554
+ */
+ public void test18566_AlgorithmOid_MissingNull_Failure() throws Exception {
X509EncodedKeySpec keySpec = new X509EncodedKeySpec(PK_BYTES);
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
PublicKey pk = keyFactory.generatePublic(keySpec);
@@ -380,7 +439,7 @@ public class SignatureTest extends TestCase {
Signature sig = Signature.getInstance("SHA256withRSA");
sig.initVerify(pk);
sig.update(CONTENT);
- assertTrue(sig.verify(SIGNATURE));
+ assertFalse(sig.verify(SIGNATURE));
}
/*
@@ -1646,4 +1705,43 @@ public class SignatureTest extends TestCase {
es.shutdown();
assertTrue("Test should not timeout", es.awaitTermination(1, TimeUnit.MINUTES));
}
+
+ public void testArbitraryCurve() throws Exception {
+ // These are the parameters for the BitCoin curve (secp256k1). See
+ // https://en.bitcoin.it/wiki/Secp256k1.
+ final BigInteger p = new BigInteger("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F", 16);
+ final BigInteger a = BigInteger.valueOf(0);
+ final BigInteger b = BigInteger.valueOf(7);
+ final BigInteger x = new BigInteger("79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798", 16);
+ final BigInteger y = new BigInteger("483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8", 16);
+ final BigInteger order = new BigInteger("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141", 16);
+ final int cofactor = 1;
+
+ final ECParameterSpec spec = new ECParameterSpec(new EllipticCurve(new ECFieldFp(p), a, b), new ECPoint(x, y), order, cofactor);
+ final KeyFactory factory = KeyFactory.getInstance("EC");
+
+ // $ openssl ecparam -name secp256k1 -genkey > key.pem
+ // $ openssl ec -text -noout < key.pem
+ final BigInteger Px = new BigInteger("2d45572747a625db5fd23b30f97044a682f2d42d31959295043c1fa0034c8ed3", 16);
+ final BigInteger Py = new BigInteger("4d330f52e4bba00145a331041c8bbcf300c4fbfdf3d63d8de7608155b2793808", 16);
+
+ final ECPublicKeySpec keySpec = new ECPublicKeySpec(new ECPoint(Px, Py), spec);
+ final PublicKey pub = factory.generatePublic(keySpec);
+
+ // $ echo -n "Satoshi Nakamoto" > signed
+ // $ openssl dgst -ecdsa-with-SHA1 -sign key.pem -out sig signed
+ final byte[] SIGNATURE = hexToBytes("304402205b41ece6dcc1c5bfcfdae74658d99c08c5e783f3926c11ecc1a8bea5d95cdf27022061a7d5fc687287e2e02dd7c6723e2e27fe0555f789590a37e96b1bb0355b4df0");
+
+ Signature ecdsaVerify = Signature.getInstance("SHA1withECDSA");
+ ecdsaVerify.initVerify(pub);
+ ecdsaVerify.update("Satoshi Nakamoto".getBytes("UTF-8"));
+ boolean result = ecdsaVerify.verify(SIGNATURE);
+ assertEquals(true, result);
+
+ ecdsaVerify = Signature.getInstance("SHA1withECDSA");
+ ecdsaVerify.initVerify(pub);
+ ecdsaVerify.update("Not Satoshi Nakamoto".getBytes("UTF-8"));
+ result = ecdsaVerify.verify(SIGNATURE);
+ assertEquals(false, result);
+ }
}
diff --git a/luni/src/test/java/libcore/java/security/cert/CertificateFactoryTest.java b/luni/src/test/java/libcore/java/security/cert/CertificateFactoryTest.java
index e2f21e8..a3a721a 100644
--- a/luni/src/test/java/libcore/java/security/cert/CertificateFactoryTest.java
+++ b/luni/src/test/java/libcore/java/security/cert/CertificateFactoryTest.java
@@ -16,11 +16,13 @@
package libcore.java.security.cert;
+import com.android.org.bouncycastle.asn1.x509.AuthorityKeyIdentifier;
import com.android.org.bouncycastle.asn1.x509.BasicConstraints;
-import com.android.org.bouncycastle.asn1.x509.X509Extensions;
+import com.android.org.bouncycastle.asn1.x509.Extension;
+import com.android.org.bouncycastle.asn1.x509.SubjectKeyIdentifier;
+import com.android.org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
import com.android.org.bouncycastle.x509.X509V3CertificateGenerator;
import com.android.org.bouncycastle.x509.extension.AuthorityKeyIdentifierStructure;
-import com.android.org.bouncycastle.x509.extension.SubjectKeyIdentifierStructure;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
@@ -28,13 +30,14 @@ import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
-import java.io.OptionalDataException;
-import java.io.StreamCorruptedException;
import java.math.BigInteger;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.Provider;
+import java.security.PublicKey;
import java.security.Security;
import java.security.cert.CertPath;
import java.security.cert.Certificate;
@@ -554,25 +557,26 @@ public class CertificateFactoryTest extends TestCase {
X509V3CertificateGenerator certGen = new X509V3CertificateGenerator();
+ PublicKey pubKey = keyPair.getPublic();
certGen.setSerialNumber(serial);
certGen.setIssuerDN(issuerPrincipal);
certGen.setNotBefore(startDate);
certGen.setNotAfter(expiryDate);
certGen.setSubjectDN(subjectPrincipal);
- certGen.setPublicKey(keyPair.getPublic());
+ certGen.setPublicKey(pubKey);
certGen.setSignatureAlgorithm("SHA1withRSA");
if (issuer != null) {
- certGen.addExtension(X509Extensions.AuthorityKeyIdentifier, false,
+ certGen.addExtension(Extension.authorityKeyIdentifier, false,
new AuthorityKeyIdentifierStructure(issuer.certificate));
} else {
- certGen.addExtension(X509Extensions.AuthorityKeyIdentifier, false,
- new AuthorityKeyIdentifierStructure(keyPair.getPublic()));
+ certGen.addExtension(Extension.authorityKeyIdentifier, false,
+ new AuthorityKeyIdentifier(generatePublicKeyDigest(pubKey)));
}
- certGen.addExtension(X509Extensions.SubjectKeyIdentifier, false,
- new SubjectKeyIdentifierStructure(keyPair.getPublic()));
- certGen.addExtension(X509Extensions.BasicConstraints, true, basicConstraints);
+ certGen.addExtension(Extension.subjectKeyIdentifier, false,
+ new SubjectKeyIdentifier(generatePublicKeyDigest(pubKey)));
+ certGen.addExtension(Extension.basicConstraints, true, basicConstraints);
X509Certificate cert = certGen.generate(caKey);
@@ -582,4 +586,18 @@ public class CertificateFactoryTest extends TestCase {
return holder;
}
+
+ /**
+ * Generates a type 1 key identifier according to RFC 3280 4.2.1.2.
+ */
+ private static byte[] generatePublicKeyDigest(PublicKey pubKey) {
+ SubjectPublicKeyInfo spki = SubjectPublicKeyInfo.getInstance(pubKey.getEncoded());
+ MessageDigest sha1digest;
+ try {
+ sha1digest = MessageDigest.getInstance("SHA-1");
+ } catch (NoSuchAlgorithmException e) {
+ throw new RuntimeException("SHA-1 not available");
+ }
+ return sha1digest.digest(spki.getPublicKeyData().getBytes());
+ }
}
diff --git a/luni/src/test/java/libcore/java/security/cert/X509CRLTest.java b/luni/src/test/java/libcore/java/security/cert/X509CRLTest.java
index 42de50a..1611120 100644
--- a/luni/src/test/java/libcore/java/security/cert/X509CRLTest.java
+++ b/luni/src/test/java/libcore/java/security/cert/X509CRLTest.java
@@ -256,15 +256,7 @@ public class X509CRLTest extends TestCase {
private void getSigAlgName(CertificateFactory f) throws Exception {
X509CRL crlRsa = getCRL(f, CRL_RSA);
-
- String actual = crlRsa.getSigAlgName().toUpperCase(Locale.US);
-
- // Bouncycastle is broken
- if ("BC".equals(f.getProvider().getName())) {
- assertEquals("1.2.840.113549.1.1.5", actual);
- } else {
- assertEquals("SHA1WITHRSA", actual);
- }
+ assertEquals("SHA1WITHRSA", getCRL(f, CRL_RSA).getSigAlgName().toUpperCase(Locale.ROOT));
}
private void getSigAlgOID(CertificateFactory f) throws Exception {
diff --git a/luni/src/test/java/libcore/java/security/cert/X509CertificateTest.java b/luni/src/test/java/libcore/java/security/cert/X509CertificateTest.java
index c35f8e6..14c22ef 100644
--- a/luni/src/test/java/libcore/java/security/cert/X509CertificateTest.java
+++ b/luni/src/test/java/libcore/java/security/cert/X509CertificateTest.java
@@ -339,6 +339,13 @@ public class X509CertificateTest extends TestCase {
Provider[] providers = Security.getProviders("Signature." + c.getSigAlgName());
for (Provider p : providers) {
+ // Do not test AndroidKeyStore Provider. It does not accept vanilla public keys for
+ // signature verification. It's OKish not to test here because it's tested by
+ // cts/tests/tests/keystore.
+ if (p.getName().startsWith("AndroidKeyStore")) {
+ continue;
+ }
+
c.verify(signer, p.getName());
try {
diff --git a/luni/src/test/java/libcore/java/sql/TimestampTest.java b/luni/src/test/java/libcore/java/sql/TimestampTest.java
index 2985848..71ac8c8 100644
--- a/luni/src/test/java/libcore/java/sql/TimestampTest.java
+++ b/luni/src/test/java/libcore/java/sql/TimestampTest.java
@@ -144,4 +144,12 @@ public final class TimestampTest extends TestCase {
} catch (IllegalArgumentException expected) { }
}
+ // http://b/19756610
+ public void testAsymmetricEquals() {
+ Timestamp timestamp = new Timestamp(0);
+ java.util.Date date = new java.util.Date(0);
+
+ assertTrue(date.equals(timestamp));
+ assertFalse(timestamp.equals(date));
+ }
}
diff --git a/luni/src/test/java/libcore/java/text/BreakIteratorTest.java b/luni/src/test/java/libcore/java/text/BreakIteratorTest.java
index 47701c8..de2ae52 100644
--- a/luni/src/test/java/libcore/java/text/BreakIteratorTest.java
+++ b/luni/src/test/java/libcore/java/text/BreakIteratorTest.java
@@ -172,32 +172,4 @@ public class BreakIteratorTest extends junit.framework.TestCase {
// Expected exception
}
}
-
- // http://code.google.com/p/android/issues/detail?id=41143
- // This code is inherently unsafe and crazy;
- // we're just trying to provoke native crashes!
- public void testConcurrentBreakIteratorAccess() throws Exception {
- final BreakIterator it = BreakIterator.getCharacterInstance();
-
- ArrayList<Thread> threads = new ArrayList<Thread>();
- for (int i = 0; i < 10; ++i) {
- Thread t = new Thread(new Runnable() {
- public void run() {
- for (int i = 0; i < 4096; ++i) {
- it.setText("some example text");
- for (int index = it.first(); index != BreakIterator.DONE; index = it.next()) {
- }
- }
- }
- });
- threads.add(t);
- }
-
- for (Thread t : threads) {
- t.start();
- }
- for (Thread t : threads) {
- t.join();
- }
- }
}
diff --git a/luni/src/test/java/libcore/java/text/DateFormatSymbolsTest.java b/luni/src/test/java/libcore/java/text/DateFormatSymbolsTest.java
index e6933e6..0c97f34 100644
--- a/luni/src/test/java/libcore/java/text/DateFormatSymbolsTest.java
+++ b/luni/src/test/java/libcore/java/text/DateFormatSymbolsTest.java
@@ -147,17 +147,17 @@ public class DateFormatSymbolsTest extends junit.framework.TestCase {
}
// http://b/7955614
- public void test_getZoneStrings_GMT_short_names() throws Exception {
+ public void test_getZoneStrings_Apia() throws Exception {
String[][] array = DateFormatSymbols.getInstance(Locale.US).getZoneStrings();
for (int i = 0; i < array.length; ++i) {
String[] row = array[i];
- // America/Santiago is somewhat arbitrary; we just want a zone we have to generate
+ // Pacific/Apia is somewhat arbitrary; we just want a zone we have to generate
// "GMT" strings for the short names.
- if (row[0].equals("America/Santiago")) {
- assertEquals("Chile Standard Time", row[1]);
- assertEquals("GMT-03:00", row[2]);
- assertEquals("Chile Summer Time", row[3]);
- assertEquals("GMT-03:00", row[4]);
+ if (row[0].equals("Pacific/Apia")) {
+ assertEquals("Apia Standard Time", row[1]);
+ assertEquals("GMT+13:00", row[2]);
+ assertEquals("Apia Daylight Time", row[3]);
+ assertEquals("GMT+14:00", row[4]);
}
}
}
diff --git a/luni/src/test/java/libcore/java/text/DecimalFormatSymbolsTest.java b/luni/src/test/java/libcore/java/text/DecimalFormatSymbolsTest.java
index 3e0aeba..b1d37f3 100644
--- a/luni/src/test/java/libcore/java/text/DecimalFormatSymbolsTest.java
+++ b/luni/src/test/java/libcore/java/text/DecimalFormatSymbolsTest.java
@@ -86,4 +86,34 @@ public class DecimalFormatSymbolsTest extends junit.framework.TestCase {
assertEquals("$", dfs.getCurrencySymbol());
assertEquals(null, dfs.getInternationalCurrencySymbol());
}
+
+ // https://code.google.com/p/android/issues/detail?id=170718
+ public void testSerializationOfMultiCharNegativeAndPercentage() throws Exception {
+ DecimalFormatSymbols dfs = new DecimalFormatSymbols(Locale.forLanguageTag("ar-AR"));
+ assertTrue(dfs.getMinusSignString().length() > 1);
+ assertTrue(dfs.getPercentString().length() > 1);
+
+ // Serialize...
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
+ new ObjectOutputStream(out).writeObject(dfs);
+ byte[] bytes = out.toByteArray();
+
+ // Deserialize...
+ ObjectInputStream in = new ObjectInputStream(new ByteArrayInputStream(bytes));
+ DecimalFormatSymbols deserializedDfs = (DecimalFormatSymbols) in.readObject();
+ assertEquals(-1, in.read());
+
+ assertEquals(dfs.getMinusSignString(), deserializedDfs.getMinusSignString());
+ assertEquals(dfs.getPercentString(), deserializedDfs.getPercentString());
+ }
+
+ // http://b/18785260
+ public void testMultiCharMinusSignAndPercentage() {
+ DecimalFormatSymbols dfs = new DecimalFormatSymbols(Locale.forLanguageTag("ar-AR"));
+ assertTrue(dfs.getMinusSignString().length() > 1);
+ assertTrue(dfs.getPercentString().length() > 1);
+
+ assertEquals('%', dfs.getPercent());
+ assertEquals('-', dfs.getMinusSign());
+ }
}
diff --git a/luni/src/test/java/libcore/java/text/NumberFormatTest.java b/luni/src/test/java/libcore/java/text/NumberFormatTest.java
index 0678e96..87fe96d 100644
--- a/luni/src/test/java/libcore/java/text/NumberFormatTest.java
+++ b/luni/src/test/java/libcore/java/text/NumberFormatTest.java
@@ -17,6 +17,7 @@
package libcore.java.text;
import java.math.BigInteger;
+import java.math.RoundingMode;
import java.text.DecimalFormat;
import java.text.DecimalFormatSymbols;
import java.text.FieldPosition;
@@ -93,6 +94,21 @@ public class NumberFormatTest extends junit.framework.TestCase {
}
}
+ public void testPercentageRounding() throws Exception {
+ NumberFormat nf = NumberFormat.getPercentInstance(Locale.US);
+ assertEquals("15%", nf.format(0.149));
+ assertEquals("14%", nf.format(0.142));
+
+ nf.setRoundingMode(RoundingMode.UP);
+ assertEquals("15%", nf.format(0.142));
+
+ nf.setRoundingMode(RoundingMode.DOWN);
+ assertEquals("14%", nf.format(0.149));
+
+ nf.setMaximumFractionDigits(1);
+ assertEquals("14.9%", nf.format(0.149));
+ }
+
// https://code.google.com/p/android/issues/detail?id=62269
public void test_62269() throws Exception {
NumberFormat nf = NumberFormat.getNumberInstance(Locale.US);
diff --git a/luni/src/test/java/libcore/java/util/CalendarTest.java b/luni/src/test/java/libcore/java/util/CalendarTest.java
index e0e1a35..2e13ad8 100644
--- a/luni/src/test/java/libcore/java/util/CalendarTest.java
+++ b/luni/src/test/java/libcore/java/util/CalendarTest.java
@@ -263,4 +263,76 @@ public class CalendarTest extends junit.framework.TestCase {
b.setTime(d);
assertEquals(a, b);
}
+
+ public void testCloneMakesDeepCopyOfCalendarFields() {
+ FakeCalendar c = new FakeCalendar();
+ FakeCalendar c2 = (FakeCalendar) c.clone();
+
+ assertFalse(c.getTimeZone() == c2.getTimeZone());
+ assertEquals(c.getTimeZone(), c2.getTimeZone());
+
+ // The default clone() implementation makes a deep copy of calendar
+ // fields...
+ assertFalse(c.getCalenderFields() == c2.getCalenderFields());
+ // ,,, and a shallow copy of subclass fields.
+ assertSame(c.getSubclassFields(), c2.getSubclassFields());
+ }
+
+ public static class FakeCalendar extends Calendar {
+
+ private int[] subclassFields;
+
+ public FakeCalendar() {
+ super(TimeZone.getDefault(), Locale.getDefault());
+ subclassFields = new int[12];
+ }
+
+ public int[] getCalenderFields() {
+ return fields;
+ }
+
+ public int[] getSubclassFields() {
+ return subclassFields;
+ }
+
+ @Override
+ public void add(int field, int value) {
+
+ }
+
+ @Override
+ protected void computeFields() {
+
+ }
+
+ @Override
+ protected void computeTime() {
+
+ }
+
+ @Override
+ public int getGreatestMinimum(int field) {
+ return 0;
+ }
+
+ @Override
+ public int getLeastMaximum(int field) {
+ return 0;
+ }
+
+ @Override
+ public int getMaximum(int field) {
+ return 0;
+ }
+
+ @Override
+ public int getMinimum(int field) {
+ return 0;
+ }
+
+ @Override
+ public void roll(int field, boolean increment) {
+
+ }
+ }
}
diff --git a/luni/src/test/java/libcore/java/util/CollectionsTest.java b/luni/src/test/java/libcore/java/util/CollectionsTest.java
index 80c769e..bc73817 100644
--- a/luni/src/test/java/libcore/java/util/CollectionsTest.java
+++ b/luni/src/test/java/libcore/java/util/CollectionsTest.java
@@ -17,7 +17,10 @@
package libcore.java.util;
import java.io.Serializable;
+import java.util.ArrayList;
import java.util.Collections;
+import java.util.Comparator;
+import java.util.ConcurrentModificationException;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.ListIterator;
@@ -94,4 +97,92 @@ public final class CollectionsTest extends TestCase {
} catch (IllegalStateException expected) {
}
}
+
+ public void testSortFastPath_incrementsModcount() {
+ ArrayList<String> list = new ArrayList<String>(16);
+ list.add("coven");
+ list.add("asylum");
+ list.add("murder house");
+ list.add("freak show");
+
+ Iterator<String> it = list.iterator();
+ it.next();
+ Collections.sort(list);
+ try {
+ it.next();
+ fail();
+ } catch (ConcurrentModificationException expected) {
+ }
+ }
+
+ /**
+ * A value type whose {@code compareTo} method returns one of {@code 0},
+ * {@code Integer.MIN_VALUE} and {@code Integer.MAX_VALUE}.
+ */
+ static final class IntegerWithExtremeComparator
+ implements Comparable<IntegerWithExtremeComparator> {
+ private final int value;
+
+ public IntegerWithExtremeComparator(int value) {
+ this.value = value;
+ }
+
+ @Override
+ public int compareTo(IntegerWithExtremeComparator another) {
+ if (another.value == this.value) {
+ return 0;
+ } else if (another.value > this.value) {
+ return Integer.MIN_VALUE;
+ } else {
+ return Integer.MAX_VALUE;
+ }
+ }
+ }
+
+ // http://b/19749094
+ public void testBinarySearch_comparatorThatReturnsMinAndMaxValue() {
+ ArrayList<Integer> list = new ArrayList<Integer>(16);
+ list.add(4);
+ list.add(9);
+ list.add(11);
+ list.add(14);
+ list.add(16);
+
+ int index = Collections.binarySearch(list, 9, new Comparator<Integer>() {
+ @Override
+ public int compare(Integer lhs, Integer rhs) {
+ final int compare = lhs.compareTo(rhs);
+ if (compare == 0) {
+ return 0;
+ } else if (compare < 0) {
+ return Integer.MIN_VALUE;
+ } else {
+ return Integer.MAX_VALUE;
+ }
+ }
+ });
+ assertEquals(1, index);
+
+ ArrayList<IntegerWithExtremeComparator> list2 =
+ new ArrayList<IntegerWithExtremeComparator>();
+ list2.add(new IntegerWithExtremeComparator(4));
+ list2.add(new IntegerWithExtremeComparator(9));
+ list2.add(new IntegerWithExtremeComparator(11));
+ list2.add(new IntegerWithExtremeComparator(14));
+ list2.add(new IntegerWithExtremeComparator(16));
+
+ assertEquals(1, Collections.binarySearch(list2, new IntegerWithExtremeComparator(9)));
+ }
+
+ public void testBinarySearch_emptyCollection() {
+ assertEquals(-1, Collections.binarySearch(new ArrayList<Integer>(), 9));
+
+ assertEquals(-1, Collections.binarySearch(new ArrayList<Integer>(), 9,
+ new Comparator<Integer>() {
+ @Override
+ public int compare(Integer lhs, Integer rhs) {
+ return lhs.compareTo(rhs);
+ }
+ }));
+ }
}
diff --git a/luni/src/test/java/libcore/java/util/CurrencyTest.java b/luni/src/test/java/libcore/java/util/CurrencyTest.java
index cf2a1b6..e4c56e5 100644
--- a/luni/src/test/java/libcore/java/util/CurrencyTest.java
+++ b/luni/src/test/java/libcore/java/util/CurrencyTest.java
@@ -58,7 +58,7 @@ public class CurrencyTest extends junit.framework.TestCase {
assertEquals("Swiss Franc", Currency.getInstance("CHF").getDisplayName(Locale.US));
assertEquals("Schweizer Franken", Currency.getInstance("CHF").getDisplayName(new Locale("de", "CH")));
assertEquals("franc suisse", Currency.getInstance("CHF").getDisplayName(new Locale("fr", "CH")));
- assertEquals("Franco Svizzero", Currency.getInstance("CHF").getDisplayName(new Locale("it", "CH")));
+ assertEquals("franco svizzero", Currency.getInstance("CHF").getDisplayName(new Locale("it", "CH")));
}
public void test_getDefaultFractionDigits() throws Exception {
diff --git a/luni/src/test/java/libcore/java/util/DateTest.java b/luni/src/test/java/libcore/java/util/DateTest.java
index 3ed0952..076c6e2 100644
--- a/luni/src/test/java/libcore/java/util/DateTest.java
+++ b/luni/src/test/java/libcore/java/util/DateTest.java
@@ -31,12 +31,13 @@ public class DateTest extends TestCase {
assertEquals("Wed Dec 31 18:00:00 CST 1969", new Date(0).toString());
}
+ // https://code.google.com/p/android/issues/detail?id=81924
public void test_toString_nonUs() {
// The string for the timezone depends on what the default locale is. Not every locale
- // has a short-name for America/Chicago -> PST.
- Locale.setDefault(Locale.UK);
+ // has a short-name for America/Chicago -> CST.
+ Locale.setDefault(Locale.CHINA);
TimeZone.setDefault(TimeZone.getTimeZone("America/Chicago"));
- assertEquals("Wed Dec 31 18:00:00 GMT-06:00 1969", new Date(0).toString());
+ assertEquals("Wed Dec 31 18:00:00 CST 1969", new Date(0).toString());
}
public void test_toGMTString_us() throws Exception {
@@ -61,10 +62,10 @@ public class DateTest extends TestCase {
Calendar c = Calendar.getInstance();
c.clear();
c.set(Calendar.YEAR, 21);
- assertEquals("Wed Jan 01 00:00:00 GMT-08:00 21", c.getTime().toString());
+ assertEquals("Wed Jan 01 00:00:00 PST 21", c.getTime().toString());
assertEquals("1 Jan 21 08:00:00 GMT", c.getTime().toGMTString());
c.set(Calendar.YEAR, 321);
- assertEquals("Sun Jan 01 00:00:00 GMT-08:00 321", c.getTime().toString());
+ assertEquals("Sun Jan 01 00:00:00 PST 321", c.getTime().toString());
assertEquals("1 Jan 321 08:00:00 GMT", c.getTime().toGMTString());
}
}
diff --git a/luni/src/test/java/libcore/java/util/LocaleTest.java b/luni/src/test/java/libcore/java/util/LocaleTest.java
index c72ecd7..9005f25 100644
--- a/luni/src/test/java/libcore/java/util/LocaleTest.java
+++ b/luni/src/test/java/libcore/java/util/LocaleTest.java
@@ -20,6 +20,7 @@ import java.text.BreakIterator;
import java.text.Collator;
import java.text.DateFormat;
import java.text.DateFormatSymbols;
+import java.text.DecimalFormatSymbols;
import java.text.NumberFormat;
import java.util.Calendar;
import java.util.IllformedLocaleException;
@@ -1146,4 +1147,94 @@ public class LocaleTest extends junit.framework.TestCase {
assertEquals("variant", locale.getVariant());
assertEquals(locale, Locale.forLanguageTag(locale.toLanguageTag()));
}
+
+ public void testArabicDigits() throws Exception {
+ // ar-DZ uses latn digits by default, but we can override that.
+ Locale ar_DZ = Locale.forLanguageTag("ar-DZ");
+ Locale ar_DZ_arab = Locale.forLanguageTag("ar-DZ-u-nu-arab");
+ Locale ar_DZ_latn = Locale.forLanguageTag("ar-DZ-u-nu-latn");
+ assertEquals('0', new DecimalFormatSymbols(ar_DZ).getZeroDigit());
+ assertEquals('\u0660', new DecimalFormatSymbols(ar_DZ_arab).getZeroDigit());
+ assertEquals('0', new DecimalFormatSymbols(ar_DZ_latn).getZeroDigit());
+
+ // ar-EG uses arab digits by default, but we can override that.
+ Locale ar_EG = Locale.forLanguageTag("ar-EG");
+ Locale ar_EG_arab = Locale.forLanguageTag("ar-EG-u-nu-arab");
+ Locale ar_EG_latn = Locale.forLanguageTag("ar-EG-u-nu-latn");
+ assertEquals('\u0660', new DecimalFormatSymbols(ar_EG).getZeroDigit());
+ assertEquals('\u0660', new DecimalFormatSymbols(ar_EG_arab).getZeroDigit());
+ assertEquals('0', new DecimalFormatSymbols(ar_EG_latn).getZeroDigit());
+ }
+
+ public void testDefaultLocale() throws Exception {
+ final String userLanguage = System.getProperty("user.language", "");
+ final String userRegion = System.getProperty("user.region", "");
+ final String userLocale = System.getProperty("user.locale", "");
+ try {
+ // Assert that user.locale gets priority.
+ System.setUnchangeableSystemProperty("user.locale", "de-DE");
+ System.setUnchangeableSystemProperty("user.language", "en");
+ System.setUnchangeableSystemProperty("user.region", "US");
+
+ Locale l = Locale.getDefaultLocaleFromSystemProperties();
+ assertEquals("de", l.getLanguage());
+ assertEquals("DE", l.getCountry());
+
+ // Assert that it's parsed as a full language tag.
+ System.setUnchangeableSystemProperty("user.locale", "de-Latn-DE");
+ System.setUnchangeableSystemProperty("user.language", "en");
+ System.setUnchangeableSystemProperty("user.region", "US");
+
+ l = Locale.getDefaultLocaleFromSystemProperties();
+ assertEquals("de", l.getLanguage());
+ assertEquals("DE", l.getCountry());
+ assertEquals("Latn", l.getScript());
+
+ // Assert that we use "und" if we're faced with a bad language tag, and
+ // that we don't end up with a null default locale or an exception.
+ System.setUnchangeableSystemProperty("user.locale", "dexx-Latn-DE");
+
+ l = Locale.getDefaultLocaleFromSystemProperties();
+ assertEquals("und", l.getLanguage());
+ assertEquals("DE", l.getCountry());
+ } finally {
+ System.setUnchangeableSystemProperty("user.language", userLanguage);
+ System.setUnchangeableSystemProperty("user.region", userRegion);
+ System.setUnchangeableSystemProperty("user.locale", userLocale);
+ }
+ }
+
+ // http://b/20252611
+ public void testLegacyLocalesWithExtensions() {
+ Locale ja_JP_JP = new Locale("ja", "JP", "JP");
+ assertEquals("ca-japanese", ja_JP_JP.getExtension(Locale.UNICODE_LOCALE_EXTENSION));
+ assertEquals("japanese", ja_JP_JP.getUnicodeLocaleType("ca"));
+
+ Locale th_TH_TH = new Locale("th", "TH", "TH");
+ assertEquals("nu-thai", th_TH_TH.getExtension(Locale.UNICODE_LOCALE_EXTENSION));
+ assertEquals("thai", th_TH_TH.getUnicodeLocaleType("nu"));
+ }
+
+ // http://b/20252611
+ public void testLowerCaseExtensionKeys() {
+ // We must lowercase extension keys in forLanguageTag..
+ Locale ar_EG = Locale.forLanguageTag("ar-EG-U-nu-arab");
+ assertEquals("nu-arab", ar_EG.getExtension(Locale.UNICODE_LOCALE_EXTENSION));
+ assertEquals("ar-EG-u-nu-arab", ar_EG.toLanguageTag());
+
+ // ... and in builders.
+ Locale.Builder b = new Locale.Builder();
+ b.setLanguage("ar");
+ b.setRegion("EG");
+ b.setExtension('U', "nu-arab");
+ assertEquals("ar-EG-u-nu-arab", b.build().toLanguageTag());
+
+ // Corollary : extension keys are case insensitive.
+ b = new Locale.Builder();
+ b.setLanguage("ar");
+ b.setRegion("EG");
+ b.setExtension('U', "nu-arab");
+ b.setExtension('u', "nu-thai");
+ assertEquals("ar-EG-u-nu-thai", b.build().toLanguageTag());
+ }
}
diff --git a/luni/src/test/java/libcore/java/util/OldTimeZoneTest.java b/luni/src/test/java/libcore/java/util/OldTimeZoneTest.java
index ecf2e5f..7a5fc4a 100644
--- a/luni/src/test/java/libcore/java/util/OldTimeZoneTest.java
+++ b/luni/src/test/java/libcore/java/util/OldTimeZoneTest.java
@@ -108,7 +108,7 @@ public class OldTimeZoneTest extends TestCase {
TimeZone tz = TimeZone.getTimeZone("America/Los_Angeles");
assertEquals("Pacific Daylight Time", tz.getDisplayName(true, TimeZone.LONG, Locale.US));
assertEquals("Pacific Standard Time", tz.getDisplayName(false, TimeZone.LONG, Locale.UK));
- assertEquals("heure avanc\u00e9e du Pacifique",
+ assertEquals("heure d’été du Pacifique",
tz.getDisplayName(true, TimeZone.LONG, Locale.FRANCE));
assertEquals("heure normale du Pacifique nord-américain",
tz.getDisplayName(false, TimeZone.LONG, Locale.FRANCE));
@@ -123,18 +123,6 @@ public class OldTimeZoneTest extends TestCase {
assertEquals("GMT-07:00", tz.getDisplayName(true, TimeZone.SHORT, Locale.FRANCE));
assertEquals("GMT-08:00", tz.getDisplayName(false, TimeZone.SHORT, Locale.UK));
assertEquals("GMT-07:00", tz.getDisplayName(true, TimeZone.SHORT, Locale.UK));
-
- // The RI behavior mentioned above does not appear to be because "PST" is a legacy
- // three-character timezone supported by the RI: it happens for "Asia/Tehran"/"IRST" too
- // (IRST is not a legacy code). The RI may just use a different dataset that has "PST" /
- // "IRST" as valid translations (even for scripts like Chinese).
- TimeZone iranTz = TimeZone.getTimeZone("Asia/Tehran");
- assertEquals("Iran Summer Time", iranTz.getDisplayName(true, TimeZone.LONG, Locale.UK));
- assertEquals("Iran Daylight Time", iranTz.getDisplayName(true, TimeZone.LONG, Locale.US));
- assertEquals("Iran Standard Time", iranTz.getDisplayName(false, TimeZone.LONG, Locale.UK));
- assertEquals("Iran Standard Time", iranTz.getDisplayName(false, TimeZone.LONG, Locale.US));
- assertEquals("GMT+03:30", iranTz.getDisplayName(false, TimeZone.SHORT, Locale.UK));
- assertEquals("GMT+04:30", iranTz.getDisplayName(true, TimeZone.SHORT, Locale.UK));
}
public void test_getID() {
diff --git a/luni/src/test/java/libcore/java/util/TimSortTest.java b/luni/src/test/java/libcore/java/util/TimSortTest.java
new file mode 100644
index 0000000..0e928ba
--- /dev/null
+++ b/luni/src/test/java/libcore/java/util/TimSortTest.java
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package libcore.java.util;
+
+import junit.framework.TestCase;
+
+import java.util.Arrays;
+import java.util.Comparator;
+
+/**
+ * This test is based on test data generated by
+ * https://github.com/abstools/java-timsort-bug/blob/master/TestTimSort.java
+ */
+public class TimSortTest extends TestCase {
+
+ private static final Comparator<Integer> NATURAL_ORDER_COMPARATOR = new Comparator<Integer>() {
+ public int compare(Integer first, Integer second) {
+ return first.compareTo(second);
+ }
+ };
+
+ private static final int BAD_DATA_SIZE = 65536;
+
+ private static int[] BAD_RUN_OFFSETS = {
+ 20204, 20221, 20237, 20255, 20289, 20363, 20521, 20837, 21469, 22733, 25260, 30315,
+ 40408, 40425, 40441, 40459, 40493, 40567, 40725, 41041, 41673, 42936, 45463, 50500,
+ 50517, 50533, 50551, 50585, 50659, 50817, 51133, 51764, 53027, 55536, 55553, 55569,
+ 55587, 55621, 55695, 55853, 56168, 56799, 58044, 58061, 58077, 58095, 58129, 58203,
+ 58360, 58675, 59288, 59305, 59321, 59339, 59373, 59446, 59603, 59900, 59917, 59933,
+ 59951, 59985, 60059, 60196, 60217, 60236, 60274, 60332, 60351, 60369, 60389, 60405,
+ };
+
+ public void testBug19493779WithComparable() throws Exception {
+ Integer[] array = createBugTriggerData();
+ Arrays.sort(array);
+ // The bug caused an ArrayIndexOutOfBoundsException, but we check this anyway.
+ assertSorted(array);
+ }
+
+ public void testBug19493779WithComparator() throws Exception {
+ Integer[] array = createBugTriggerData();
+ Arrays.sort(array, NATURAL_ORDER_COMPARATOR);
+ // The bug caused an ArrayIndexOutOfBoundsException, but we check this anyway.
+ assertSorted(array);
+ }
+
+ private static void assertSorted(Integer[] arrayToSort) {
+ for (int i = 1; i < arrayToSort.length; i++) {
+ if (arrayToSort[i - 1] > arrayToSort[i]) {
+ fail("Array not sorted at element " + i + ": " + Arrays.toString(arrayToSort));
+ }
+ }
+ }
+
+ private static Integer[] createBugTriggerData() {
+ final Integer zero = 0;
+ final Integer one = 1;
+
+ Integer[] bugTriggerData = new Integer[BAD_DATA_SIZE];
+ for (int i = 0; i < bugTriggerData.length; i++) {
+ bugTriggerData[i] = zero;
+ }
+
+ for (int i = 0; i < BAD_RUN_OFFSETS.length; i++) {
+ bugTriggerData[BAD_RUN_OFFSETS[i]] = one;
+ }
+ return bugTriggerData;
+ }
+} \ No newline at end of file
diff --git a/luni/src/test/java/libcore/java/util/TimeZoneTest.java b/luni/src/test/java/libcore/java/util/TimeZoneTest.java
index 1ca950c..68e9109 100644
--- a/luni/src/test/java/libcore/java/util/TimeZoneTest.java
+++ b/luni/src/test/java/libcore/java/util/TimeZoneTest.java
@@ -73,6 +73,12 @@ public class TimeZoneTest extends TestCase {
assertFalse(tz.inDaylightTime(date));
}
+ public void testGetDisplayNameShort_nonHourOffsets() {
+ TimeZone iranTz = TimeZone.getTimeZone("Asia/Tehran");
+ assertEquals("GMT+03:30", iranTz.getDisplayName(false, TimeZone.SHORT, Locale.UK));
+ assertEquals("GMT+04:30", iranTz.getDisplayName(true, TimeZone.SHORT, Locale.UK));
+ }
+
public void testPreHistoricOffsets() throws Exception {
// "Africa/Bissau" has just a few transitions and hasn't changed in a long time.
// 1912-01-01 00:02:19-0100 ... 1912-01-01 00:02:20-0100
@@ -256,12 +262,12 @@ public class TimeZoneTest extends TestCase {
}
// http://b/7955614
- public void test_getDisplayName_GMT_short_names() throws Exception {
- TimeZone tz = TimeZone.getTimeZone("America/Santiago");
- assertEquals("Chile Summer Time", tz.getDisplayName(true, TimeZone.LONG, Locale.US));
- assertEquals("Chile Standard Time", tz.getDisplayName(false, TimeZone.LONG, Locale.US));
- assertEquals("GMT-03:00", tz.getDisplayName(true, TimeZone.SHORT, Locale.US));
- assertEquals("GMT-03:00", tz.getDisplayName(false, TimeZone.SHORT, Locale.US));
+ public void testApia() throws Exception {
+ TimeZone tz = TimeZone.getTimeZone("Pacific/Apia");
+ assertEquals("Apia Daylight Time", tz.getDisplayName(true, TimeZone.LONG, Locale.US));
+ assertEquals("Apia Standard Time", tz.getDisplayName(false, TimeZone.LONG, Locale.US));
+ assertEquals("GMT+14:00", tz.getDisplayName(true, TimeZone.SHORT, Locale.US));
+ assertEquals("GMT+13:00", tz.getDisplayName(false, TimeZone.SHORT, Locale.US));
}
private static boolean isGmtString(String s) {
@@ -290,4 +296,32 @@ public class TimeZoneTest extends TestCase {
}
}
}
+
+ // http://b/18839557
+ public void testOverflowing32BitUnixDates() {
+ final TimeZone tz = TimeZone.getTimeZone("America/New_York");
+
+ // This timezone didn't have any daylight savings prior to 1917 and this
+ // date is sometime in 1901.
+ assertFalse(tz.inDaylightTime(new Date(-2206292400000L)));
+ assertEquals(-18000000, tz.getOffset(-2206292400000L));
+
+ // Nov 30th 2039, no daylight savings as per current rules.
+ assertFalse(tz.inDaylightTime(new Date(2206292400000L)));
+ assertEquals(-18000000, tz.getOffset(2206292400000L));
+ }
+
+ public void testTimeZoneIDLocalization() {
+ Locale defaultLocale = Locale.getDefault();
+ try {
+ Locale.setDefault(new Locale("en"));
+ TimeZone en_timezone = TimeZone.getTimeZone("GMT+09:00");
+ Locale.setDefault(new Locale("ar"));
+ TimeZone ar_timezone = TimeZone.getTimeZone("GMT+09:00");
+
+ assertEquals(en_timezone.getID(), ar_timezone.getID());
+ } finally {
+ Locale.setDefault(defaultLocale);
+ }
+ }
}
diff --git a/luni/src/test/java/libcore/java/util/jar/StrictJarFileTest.java b/luni/src/test/java/libcore/java/util/jar/StrictJarFileTest.java
index e5a6cd8..9496ad0 100644
--- a/luni/src/test/java/libcore/java/util/jar/StrictJarFileTest.java
+++ b/luni/src/test/java/libcore/java/util/jar/StrictJarFileTest.java
@@ -169,6 +169,10 @@ public class StrictJarFileTest extends TestCase {
assertThrowsOnInit("Modified_SF_EntryAttributes.jar");
}
+ public void testJarSigning_removedEntry() throws Exception {
+ assertThrowsOnInit("removed.jar");
+ }
+
private void assertThrowsOnInit(String name) throws Exception {
Support_Resources.copyFile(resources, null, name);
try {
diff --git a/luni/src/test/java/libcore/java/util/zip/AbstractZipFileTest.java b/luni/src/test/java/libcore/java/util/zip/AbstractZipFileTest.java
new file mode 100644
index 0000000..9e049c0
--- /dev/null
+++ b/luni/src/test/java/libcore/java/util/zip/AbstractZipFileTest.java
@@ -0,0 +1,548 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package libcore.java.util.zip;
+
+import java.io.BufferedOutputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.Enumeration;
+import java.util.HashSet;
+import java.util.Random;
+import java.util.Set;
+import java.util.zip.CRC32;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipException;
+import java.util.zip.ZipFile;
+import java.util.zip.ZipInputStream;
+import java.util.zip.ZipOutputStream;
+import junit.framework.TestCase;
+
+import tests.support.resource.Support_Resources;
+
+public abstract class AbstractZipFileTest extends TestCase {
+ /**
+ * Exercise Inflater's ability to refill the zlib's input buffer. As of this
+ * writing, this buffer's max size is 64KiB compressed bytes. We'll write a
+ * full megabyte of uncompressed data, which should be sufficient to exhaust
+ * the buffer. http://b/issue?id=2734751
+ */
+ public void testInflatingFilesRequiringZipRefill() throws IOException {
+ int originalSize = 1024 * 1024;
+ byte[] readBuffer = new byte[8192];
+ final File f = createTemporaryZipFile();
+ writeEntries(createZipOutputStream(f), 1, originalSize, false /* setEntrySize */);
+ ZipFile zipFile = new ZipFile(f);
+ for (Enumeration<? extends ZipEntry> e = zipFile.entries(); e.hasMoreElements(); ) {
+ ZipEntry zipEntry = e.nextElement();
+ assertTrue("This test needs >64 KiB of compressed data to exercise Inflater",
+ zipEntry.getCompressedSize() > (64 * 1024));
+ InputStream is = zipFile.getInputStream(zipEntry);
+ while (is.read(readBuffer, 0, readBuffer.length) != -1) {}
+ is.close();
+ }
+ zipFile.close();
+ }
+
+ private static void replaceBytes(byte[] buffer, byte[] original, byte[] replacement) {
+ // Gotcha here: original and replacement must be the same length
+ assertEquals(original.length, replacement.length);
+ boolean found;
+ for(int i=0; i < buffer.length - original.length; i++) {
+ found = false;
+ if (buffer[i] == original[0]) {
+ found = true;
+ for (int j=0; j < original.length; j++) {
+ if (buffer[i+j] != original[j]) {
+ found = false;
+ break;
+ }
+ }
+ }
+ if (found) {
+ for (int j=0; j < original.length; j++) {
+ buffer[i+j] = replacement[j];
+ }
+ }
+ }
+ }
+
+ private static void writeBytes(File f, byte[] bytes) throws IOException {
+ FileOutputStream out = new FileOutputStream(f);
+ out.write(bytes);
+ out.close();
+ }
+
+ /**
+ * Make sure we don't fail silently for duplicate entries.
+ * b/8219321
+ */
+ public void testDuplicateEntries() throws Exception {
+ String name1 = "test_file_name1";
+ String name2 = "test_file_name2";
+
+ // Create the good zip file.
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ ZipOutputStream out = createZipOutputStream(baos);
+ out.putNextEntry(new ZipEntry(name2));
+ out.closeEntry();
+ out.putNextEntry(new ZipEntry(name1));
+ out.closeEntry();
+ out.close();
+
+ // Rewrite one of the filenames.
+ byte[] buffer = baos.toByteArray();
+ replaceBytes(buffer, name2.getBytes(), name1.getBytes());
+
+ // Write the result to a file.
+ File badZip = createTemporaryZipFile();
+ writeBytes(badZip, buffer);
+
+ // Check that we refuse to load the modified file.
+ try {
+ ZipFile bad = new ZipFile(badZip);
+ fail();
+ } catch (ZipException expected) {
+ }
+ }
+
+ /**
+ * Make sure the size used for stored zip entires is the uncompressed size.
+ * b/10227498
+ */
+ public void testStoredEntrySize() throws Exception {
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ ZipOutputStream out = createZipOutputStream(baos);
+
+ // Set up a single stored entry.
+ String name = "test_file";
+ int expectedLength = 5;
+ ZipEntry outEntry = new ZipEntry(name);
+ byte[] buffer = new byte[expectedLength];
+ outEntry.setMethod(ZipEntry.STORED);
+ CRC32 crc = new CRC32();
+ crc.update(buffer);
+ outEntry.setCrc(crc.getValue());
+ outEntry.setSize(buffer.length);
+
+ out.putNextEntry(outEntry);
+ out.write(buffer);
+ out.closeEntry();
+ out.close();
+
+ // Write the result to a file.
+ byte[] outBuffer = baos.toByteArray();
+ File zipFile = createTemporaryZipFile();
+ writeBytes(zipFile, outBuffer);
+
+ ZipFile zip = new ZipFile(zipFile);
+ // Set up the zip entry to have different compressed/uncompressed sizes.
+ ZipEntry ze = zip.getEntry(name);
+ ze.setCompressedSize(expectedLength - 1);
+ // Read the contents of the stream and verify uncompressed size was used.
+ InputStream stream = zip.getInputStream(ze);
+ int count = 0;
+ int read;
+ while ((read = stream.read(buffer)) != -1) {
+ count += read;
+ }
+
+ assertEquals(expectedLength, count);
+ zip.close();
+ }
+
+ public void testInflatingStreamsRequiringZipRefill() throws IOException {
+ int originalSize = 1024 * 1024;
+ byte[] readBuffer = new byte[8192];
+ final File f = createTemporaryZipFile();
+ writeEntries(createZipOutputStream(f), 1, originalSize, false /* setEntrySize */);
+
+ ZipInputStream in = new ZipInputStream(new FileInputStream(f));
+ while (in.getNextEntry() != null) {
+ while (in.read(readBuffer, 0, readBuffer.length) != -1) {}
+ }
+ in.close();
+ }
+
+ public void testZipFileWithLotsOfEntries() throws IOException {
+ int expectedEntryCount = 64*1024 - 1;
+ final File f = createTemporaryZipFile();
+ writeEntries(createZipOutputStream(f), expectedEntryCount, 0, false /* setEntrySize */);
+ ZipFile zipFile = new ZipFile(f);
+ int entryCount = 0;
+ for (Enumeration<? extends ZipEntry> e = zipFile.entries(); e.hasMoreElements(); ) {
+ ZipEntry zipEntry = e.nextElement();
+ ++entryCount;
+ }
+ assertEquals(expectedEntryCount, entryCount);
+ zipFile.close();
+ }
+
+ // http://code.google.com/p/android/issues/detail?id=36187
+ public void testZipFileLargerThan2GiB() throws IOException {
+ if (false) { // TODO: this test requires too much time and too much disk space!
+ final File f = createTemporaryZipFile();
+ writeEntries(createZipOutputStream(f), 1024, 3*1024*1024, false /* setEntrySize */);
+ ZipFile zipFile = new ZipFile(f);
+ int entryCount = 0;
+ for (Enumeration<? extends ZipEntry> e = zipFile.entries(); e.hasMoreElements(); ) {
+ e.nextElement();
+ ++entryCount;
+ }
+ assertEquals(1024, entryCount);
+ zipFile.close();
+ }
+ }
+
+ /**
+ * Compresses the given number of files, each of the given size, into a .zip archive.
+ */
+ protected void writeEntries(ZipOutputStream out, int entryCount, long entrySize,
+ boolean setEntrySize)
+ throws IOException {
+ byte[] writeBuffer = new byte[8192];
+ Random random = new Random();
+ try {
+ for (int entry = 0; entry < entryCount; ++entry) {
+ ZipEntry ze = new ZipEntry(Integer.toHexString(entry));
+ if (setEntrySize) {
+ ze.setSize(entrySize);
+ }
+ out.putNextEntry(ze);
+
+ for (long i = 0; i < entrySize; i += writeBuffer.length) {
+ random.nextBytes(writeBuffer);
+ int byteCount = (int) Math.min(writeBuffer.length, entrySize - i);
+ out.write(writeBuffer, 0, byteCount);
+ }
+
+ out.closeEntry();
+ }
+ } finally {
+ out.close();
+ }
+ }
+
+ static File createTemporaryZipFile() throws IOException {
+ File result = File.createTempFile("ZipFileTest", ".zip");
+ result.deleteOnExit();
+ return result;
+ }
+
+ private ZipOutputStream createZipOutputStream(File f) throws IOException {
+ return createZipOutputStream(new BufferedOutputStream(new FileOutputStream(f)));
+ }
+
+ protected abstract ZipOutputStream createZipOutputStream(OutputStream wrapped);
+
+ public void testSTORED() throws IOException {
+ ZipOutputStream out = createZipOutputStream(createTemporaryZipFile());
+ CRC32 crc = new CRC32();
+
+ // Missing CRC, size, and compressed size => failure.
+ try {
+ ZipEntry ze = new ZipEntry("a");
+ ze.setMethod(ZipEntry.STORED);
+ out.putNextEntry(ze);
+ fail();
+ } catch (ZipException expected) {
+ }
+
+ // Missing CRC and compressed size => failure.
+ try {
+ ZipEntry ze = new ZipEntry("a");
+ ze.setMethod(ZipEntry.STORED);
+ ze.setSize(0);
+ out.putNextEntry(ze);
+ fail();
+ } catch (ZipException expected) {
+ }
+
+ // Missing CRC and size => failure.
+ try {
+ ZipEntry ze = new ZipEntry("a");
+ ze.setMethod(ZipEntry.STORED);
+ ze.setSize(0);
+ ze.setCompressedSize(0);
+ out.putNextEntry(ze);
+ fail();
+ } catch (ZipException expected) {
+ }
+
+ // Missing size and compressed size => failure.
+ try {
+ ZipEntry ze = new ZipEntry("a");
+ ze.setMethod(ZipEntry.STORED);
+ ze.setCrc(crc.getValue());
+ out.putNextEntry(ze);
+ fail();
+ } catch (ZipException expected) {
+ }
+
+ // Missing size is copied from compressed size.
+ {
+ ZipEntry ze = new ZipEntry("okay1");
+ ze.setMethod(ZipEntry.STORED);
+ ze.setCrc(crc.getValue());
+
+ assertEquals(-1, ze.getSize());
+ assertEquals(-1, ze.getCompressedSize());
+
+ ze.setCompressedSize(0);
+
+ assertEquals(-1, ze.getSize());
+ assertEquals(0, ze.getCompressedSize());
+
+ out.putNextEntry(ze);
+
+ assertEquals(0, ze.getSize());
+ assertEquals(0, ze.getCompressedSize());
+ }
+
+ // Missing compressed size is copied from size.
+ {
+ ZipEntry ze = new ZipEntry("okay2");
+ ze.setMethod(ZipEntry.STORED);
+ ze.setCrc(crc.getValue());
+
+ assertEquals(-1, ze.getSize());
+ assertEquals(-1, ze.getCompressedSize());
+
+ ze.setSize(0);
+
+ assertEquals(0, ze.getSize());
+ assertEquals(-1, ze.getCompressedSize());
+
+ out.putNextEntry(ze);
+
+ assertEquals(0, ze.getSize());
+ assertEquals(0, ze.getCompressedSize());
+ }
+
+ // Mismatched size and compressed size => failure.
+ try {
+ ZipEntry ze = new ZipEntry("a");
+ ze.setMethod(ZipEntry.STORED);
+ ze.setCrc(crc.getValue());
+ ze.setCompressedSize(1);
+ ze.setSize(0);
+ out.putNextEntry(ze);
+ fail();
+ } catch (ZipException expected) {
+ }
+
+ // Everything present => success.
+ ZipEntry ze = new ZipEntry("okay");
+ ze.setMethod(ZipEntry.STORED);
+ ze.setCrc(crc.getValue());
+ ze.setSize(0);
+ ze.setCompressedSize(0);
+ out.putNextEntry(ze);
+
+ out.close();
+ }
+
+ private String makeString(int count, String ch) {
+ StringBuilder sb = new StringBuilder();
+ for (int i = 0; i < count; ++i) {
+ sb.append(ch);
+ }
+ return sb.toString();
+ }
+
+ public void testComments() throws Exception {
+ String expectedFileComment = "1 \u0666 2";
+ String expectedEntryComment = "a \u0666 b";
+
+ File file = createTemporaryZipFile();
+ ZipOutputStream out = createZipOutputStream(file);
+
+ // Is file comment length checking done on bytes or characters? (Should be bytes.)
+ out.setComment(null);
+ out.setComment(makeString(0xffff, "a"));
+ try {
+ out.setComment(makeString(0xffff + 1, "a"));
+ fail();
+ } catch (IllegalArgumentException expected) {
+ }
+ try {
+ out.setComment(makeString(0xffff, "\u0666"));
+ fail();
+ } catch (IllegalArgumentException expected) {
+ }
+
+ ZipEntry ze = new ZipEntry("a");
+
+ // Is entry comment length checking done on bytes or characters? (Should be bytes.)
+ ze.setComment(null);
+ ze.setComment(makeString(0xffff, "a"));
+ try {
+ ze.setComment(makeString(0xffff + 1, "a"));
+ fail();
+ } catch (IllegalArgumentException expected) {
+ }
+ try {
+ ze.setComment(makeString(0xffff, "\u0666"));
+ fail();
+ } catch (IllegalArgumentException expected) {
+ }
+
+ ze.setComment(expectedEntryComment);
+ out.putNextEntry(ze);
+ out.closeEntry();
+
+ out.setComment(expectedFileComment);
+ out.close();
+
+ ZipFile zipFile = new ZipFile(file);
+ assertEquals(expectedFileComment, zipFile.getComment());
+ assertEquals(expectedEntryComment, zipFile.getEntry("a").getComment());
+ zipFile.close();
+ }
+
+ public void test_getComment_unset() throws Exception {
+ File file = createTemporaryZipFile();
+ ZipOutputStream out = createZipOutputStream(file);
+ ZipEntry ze = new ZipEntry("test entry");
+ ze.setComment("per-entry comment");
+ out.putNextEntry(ze);
+ out.close();
+
+ ZipFile zipFile = new ZipFile(file);
+ assertEquals(null, zipFile.getComment());
+ }
+
+ // https://code.google.com/p/android/issues/detail?id=58465
+ public void test_NUL_in_filename() throws Exception {
+ File file = createTemporaryZipFile();
+
+ // We allow creation of a ZipEntry whose name contains a NUL byte,
+ // mainly because it's not likely to happen by accident and it's useful for testing.
+ ZipOutputStream out = createZipOutputStream(file);
+ out.putNextEntry(new ZipEntry("hello"));
+ out.putNextEntry(new ZipEntry("hello\u0000"));
+ out.close();
+
+ // But you can't open a ZIP file containing such an entry, because we reject it
+ // when we find it in the central directory.
+ try {
+ ZipFile zipFile = new ZipFile(file);
+ fail();
+ } catch (ZipException expected) {
+ }
+ }
+
+ public void testCrc() throws IOException {
+ ZipEntry ze = new ZipEntry("test");
+ ze.setMethod(ZipEntry.STORED);
+ ze.setSize(4);
+
+ // setCrc takes a long, not an int, so -1 isn't a valid CRC32 (because it's 64 bits).
+ try {
+ ze.setCrc(-1);
+ } catch (IllegalArgumentException expected) {
+ }
+
+ // You can set the CRC32 to 0xffffffff if you're slightly more careful though...
+ ze.setCrc(0xffffffffL);
+ assertEquals(0xffffffffL, ze.getCrc());
+
+ // And it actually works, even though we use -1L to mean "no CRC set"...
+ ZipOutputStream out = createZipOutputStream(createTemporaryZipFile());
+ out.putNextEntry(ze);
+ out.write(-1);
+ out.write(-1);
+ out.write(-1);
+ out.write(-1);
+ out.closeEntry();
+ out.close();
+ }
+
+ /**
+ * RI does not allow reading of an empty zip using a {@link ZipFile}.
+ */
+ public void testConstructorFailsWhenReadingEmptyZipArchive() throws IOException {
+
+ File resources = Support_Resources.createTempFolder();
+ File emptyZip = Support_Resources.copyFile(
+ resources, "java/util/zip", "EmptyArchive.zip");
+
+ try {
+ // The following should fail with an exception but if it doesn't then we need to clean
+ // up the resource so we need a reference to it.
+ ZipFile zipFile = new ZipFile(emptyZip);
+
+ // Clean up the resource.
+ try {
+ zipFile.close();
+ } catch (Exception e) {
+ // Ignore
+ }
+ fail();
+ } catch (ZipException expected) {
+ // expected
+ }
+ }
+
+ // Demonstrates http://b/18644314 : Zip entry names are relative to the point of
+ // extraction and can contain relative paths "../" and "./".
+ //
+ // It is left to callers of the API to perform any validation / santization to
+ // ensure that files are not written outside of the destination directory, where that
+ // is a concern.
+ public void testArchivesWithRelativePaths() throws IOException {
+ String[] entryNames = {
+ "../",
+ "../foo.bar",
+ "foo/../../",
+ "foo/../../bar.baz"
+ };
+
+ File zip = createTemporaryZipFile();
+ ZipOutputStream out = createZipOutputStream(zip);
+
+ try {
+ byte[] entryData = new byte[1024];
+ for (String entryName : entryNames) {
+ ZipEntry ze = new ZipEntry(entryName);
+ out.putNextEntry(ze);
+ out.write(entryData);
+ out.closeEntry();
+ }
+ } finally {
+ out.close();
+ }
+
+ ZipFile zf = new ZipFile(zip, ZipFile.OPEN_READ);
+ Enumeration<? extends ZipEntry> entries = zf.entries();
+ Set<String> entryNamesFromFile = new HashSet<>();
+ while (entries.hasMoreElements()) {
+ ZipEntry ze = entries.nextElement();
+ entryNamesFromFile.add(ze.getName());
+ }
+
+ zf.close();
+
+ for (String entryName : entryNames) {
+ assertTrue(entryNamesFromFile.contains(entryName));
+ }
+ }
+}
diff --git a/luni/src/test/java/libcore/java/util/zip/DeflaterTest.java b/luni/src/test/java/libcore/java/util/zip/DeflaterTest.java
index 30aa7f3..1dfa775 100644
--- a/luni/src/test/java/libcore/java/util/zip/DeflaterTest.java
+++ b/luni/src/test/java/libcore/java/util/zip/DeflaterTest.java
@@ -82,4 +82,26 @@ public class DeflaterTest extends TestCase {
assertTrue(totalDeflated > 0); // the deflated form should be non-empty
assertEquals(0, totalInflated);
}
+
+ public void testDeflaterCounts() throws Exception {
+ deflater.setInput(new byte[] { 1, 2, 3 });
+ assertEquals(11, deflater.deflate(compressed, 0, compressed.length, Deflater.FULL_FLUSH));
+ assertEquals(3, deflater.getBytesRead());
+ assertEquals(3, deflater.getTotalIn());
+ assertEquals(11, deflater.getBytesWritten());
+ assertEquals(11, deflater.getTotalOut());
+
+ deflater.setInput(new byte[] { 1, 2, 3 });
+ assertEquals(9, deflater.deflate(compressed, 0, compressed.length, Deflater.FULL_FLUSH));
+ assertEquals(6, deflater.getBytesRead());
+ assertEquals(6, deflater.getTotalIn());
+ assertEquals(20, deflater.getBytesWritten());
+
+
+ deflater.reset();
+ assertEquals(0, deflater.getBytesRead());
+ assertEquals(0, deflater.getBytesWritten());
+ assertEquals(0, deflater.getTotalIn());
+ assertEquals(0, deflater.getTotalOut());
+ }
}
diff --git a/luni/src/test/java/libcore/java/util/zip/GZIPInputStreamTest.java b/luni/src/test/java/libcore/java/util/zip/GZIPInputStreamTest.java
index 494520a..5813753 100644
--- a/luni/src/test/java/libcore/java/util/zip/GZIPInputStreamTest.java
+++ b/luni/src/test/java/libcore/java/util/zip/GZIPInputStreamTest.java
@@ -35,14 +35,46 @@ import libcore.io.Streams;
public final class GZIPInputStreamTest extends TestCase {
private static final byte[] HELLO_WORLD_GZIPPED = new byte[] {
- 31, -117, 8, 0, 0, 0, 0, 0, 0, 0, -13, 72, -51, -55, -55, 87, 8, -49,
- 47, -54, 73, 1, 0, 86, -79, 23, 74, 11, 0, 0, 0
+ 31, -117, 8, 0, 0, 0, 0, 0, 0, 0, // 10 byte header
+ -13, 72, -51, -55, -55, 87, 8, -49, 47, -54, 73, 1, 0, 86, -79, 23, 74, 11, 0, 0, 0 // data
+ };
+
+ /**
+ * This is the same as the above, except that the 4th header byte is 2 (FHCRC flag)
+ * and the 2 bytes after the header make up the CRC.
+ *
+ * Constructed manually because none of the commonly used tools appear to emit header CRCs.
+ */
+ private static final byte[] HELLO_WORLD_GZIPPED_WITH_HEADER_CRC = new byte[] {
+ 31, -117, 8, 2, 0, 0, 0, 0, 0, 0, // 10 byte header
+ 29, 38, // 2 byte CRC.
+ -13, 72, -51, -55, -55, 87, 8, -49, 47, -54, 73, 1, 0, 86, -79, 23, 74, 11, 0, 0, 0 // data
+ };
+
+ /*(
+ * This is the same as {@code HELLO_WORLD_GZIPPED} except that the 4th header byte is 4
+ * (FEXTRA flag) and that the 8 bytes after the header make up the extra.
+ *
+ * Constructed manually because none of the commonly used tools appear to emit header CRCs.
+ */
+ private static final byte[] HELLO_WORLD_GZIPPED_WITH_EXTRA = new byte[] {
+ 31, -117, 8, 4, 0, 0, 0, 0, 0, 0, // 10 byte header
+ 6, 0, 4, 2, 4, 2, 4, 2, // 2 byte extra length + 6 byte extra.
+ -13, 72, -51, -55, -55, 87, 8, -49, 47, -54, 73, 1, 0, 86, -79, 23, 74, 11, 0, 0, 0 // data
};
public void testShortMessage() throws IOException {
assertEquals("Hello World", new String(gunzip(HELLO_WORLD_GZIPPED), "UTF-8"));
}
+ public void testShortMessageWithCrc() throws IOException {
+ assertEquals("Hello World", new String(gunzip(HELLO_WORLD_GZIPPED_WITH_HEADER_CRC), "UTF-8"));
+ }
+
+ public void testShortMessageWithHeaderExtra() throws IOException {
+ assertEquals("Hello World", new String(gunzip(HELLO_WORLD_GZIPPED_WITH_EXTRA), "UTF-8"));
+ }
+
public void testLongMessage() throws IOException {
byte[] data = new byte[1024 * 1024];
new Random().nextBytes(data);
diff --git a/luni/src/test/java/libcore/java/util/zip/InflaterTest.java b/luni/src/test/java/libcore/java/util/zip/InflaterTest.java
index 158b3e9..cce08f3 100644
--- a/luni/src/test/java/libcore/java/util/zip/InflaterTest.java
+++ b/luni/src/test/java/libcore/java/util/zip/InflaterTest.java
@@ -122,4 +122,35 @@ public class InflaterTest extends TestCase {
adler32.update(bytes);
return (int) adler32.getValue();
}
+
+ public void testInflaterCounts() throws Exception {
+ Inflater inflater = new Inflater();
+
+ byte[] decompressed = new byte[32];
+ byte[] compressed = deflate(new byte[] { 1, 2, 3}, null);
+ assertEquals(11, compressed.length);
+
+ // Feed in bytes [0, 5) to the first iteration.
+ inflater.setInput(compressed, 0, 5);
+ inflater.inflate(decompressed, 0, decompressed.length);
+ assertEquals(5, inflater.getBytesRead());
+ assertEquals(5, inflater.getTotalIn());
+ assertEquals(2, inflater.getBytesWritten());
+ assertEquals(2, inflater.getTotalOut());
+
+ // Feed in bytes [5, 11) to the second iteration.
+ assertEquals(true, inflater.needsInput());
+ inflater.setInput(compressed, 5, 6);
+ assertEquals(1, inflater.inflate(decompressed, 0, decompressed.length));
+ assertEquals(11, inflater.getBytesRead());
+ assertEquals(11, inflater.getTotalIn());
+ assertEquals(3, inflater.getBytesWritten());
+ assertEquals(3, inflater.getTotalOut());
+
+ inflater.reset();
+ assertEquals(0, inflater.getBytesRead());
+ assertEquals(0, inflater.getTotalIn());
+ assertEquals(0, inflater.getBytesWritten());
+ assertEquals(0, inflater.getTotalOut());
+ }
}
diff --git a/luni/src/test/java/libcore/java/util/zip/Zip64FileTest.java b/luni/src/test/java/libcore/java/util/zip/Zip64FileTest.java
new file mode 100644
index 0000000..1b733f9
--- /dev/null
+++ b/luni/src/test/java/libcore/java/util/zip/Zip64FileTest.java
@@ -0,0 +1,102 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package libcore.java.util.zip;
+
+import java.io.BufferedOutputStream;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.util.Enumeration;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipFile;
+import java.util.zip.ZipOutputStream;
+
+public final class Zip64FileTest extends AbstractZipFileTest {
+ @Override
+ protected ZipOutputStream createZipOutputStream(OutputStream wrapped) {
+ return new ZipOutputStream(wrapped, true /* forceZip64 */);
+ }
+
+ public void testZip64Support_largeNumberOfEntries() throws IOException {
+ final File file = createZipFile(65550, 2, false /* setEntrySize */);
+ ZipFile zf = null;
+ try {
+ zf = new ZipFile(file);
+ assertEquals(65550, zf.size());
+
+ Enumeration<? extends ZipEntry> entries = zf.entries();
+ assertTrue(entries.hasMoreElements());
+ ZipEntry ze = entries.nextElement();
+ assertEquals(2, ze.getSize());
+ } finally {
+ if (zf != null) {
+ zf.close();
+ }
+ }
+ }
+
+ public void testZip64Support_totalLargerThan4G() throws IOException {
+ final File file = createZipFile(5, 1073741824L, false /* setEntrySize */);
+ ZipFile zf = null;
+ try {
+ zf = new ZipFile(file);
+ assertEquals(5, zf.size());
+ Enumeration<? extends ZipEntry> entries = zf.entries();
+ assertTrue(entries.hasMoreElements());
+ ZipEntry ze = entries.nextElement();
+ assertEquals(1073741824L, ze.getSize());
+ } finally {
+ if (zf != null) {
+ zf.close();
+ }
+ }
+ }
+
+ public void testZip64Support_hugeEntry() throws IOException {
+ try {
+ createZipFile(1, 4294967410L, false /* setEntrySize */);
+ fail();
+ } catch (IOException expected) {
+ }
+
+ final File file = createZipFile(1, 4294967410L, true /* setEntrySize */);
+ ZipFile zf = null;
+ try {
+ zf = new ZipFile(file);
+ assertEquals(1, zf.size());
+ Enumeration<? extends ZipEntry> entries = zf.entries();
+ assertTrue(entries.hasMoreElements());
+ ZipEntry ze = entries.nextElement();
+ assertEquals(4294967410L, ze.getSize());
+ } finally {
+ if (zf != null) {
+ zf.close();
+ }
+ }
+ }
+
+ private File createZipFile(int numEntries, long entrySize, boolean setEntrySize)
+ throws IOException {
+ File file = createTemporaryZipFile();
+ // Don't force a 64 bit zip file to test that our heuristics work.
+ ZipOutputStream os = new ZipOutputStream(
+ new BufferedOutputStream(new FileOutputStream(file)));
+ writeEntries(os, numEntries, entrySize, setEntrySize);
+ return file;
+ }
+}
diff --git a/luni/src/test/java/libcore/java/util/zip/Zip64Test.java b/luni/src/test/java/libcore/java/util/zip/Zip64Test.java
new file mode 100644
index 0000000..e4b5baf
--- /dev/null
+++ b/luni/src/test/java/libcore/java/util/zip/Zip64Test.java
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package libcore.java.util.zip;
+
+import junit.framework.TestCase;
+
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.util.zip.Zip64;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipException;
+
+public class Zip64Test extends TestCase {
+
+ // We shouldn't attempt to look inside the extended info if we have valid fields
+ // in the regular file header / central directory entry.
+ public void testParseZip64ExtendedInfo_noFieldsPresent() throws Exception {
+ ZipEntry ze = createZipEntry(null, 100, 200, ZipEntry.STORED, 300);
+ Zip64.parseZip64ExtendedInfo(ze, false /* fromCentralDirectory */);
+ Zip64.parseZip64ExtendedInfo(ze, true /* fromCentralDirectory */);
+ }
+
+ // We *should* attempt to look in the extended info if the local file header / central
+ // directory entry don't have the correct values.
+ public void testParseZip64ExtendedInfo_missingExtendedInfo() throws Exception {
+ ZipEntry ze = createZipEntry(null, Zip64.MAX_ZIP_ENTRY_AND_ARCHIVE_SIZE,
+ Zip64.MAX_ZIP_ENTRY_AND_ARCHIVE_SIZE, ZipEntry.STORED, 300);
+ try {
+ Zip64.parseZip64ExtendedInfo(ze, false /* fromCentralDirectory */);
+ fail();
+ } catch (ZipException expected) {
+ }
+
+ try {
+ Zip64.parseZip64ExtendedInfo(ze, true /* fromCentralDirectory */);
+ fail();
+ } catch (ZipException expected) {
+ }
+ }
+
+ // Test the case where the compressed / uncompressed sizes are in the extended info
+ // but the header offset isn't.
+ public void testParseZip64ExtendedInfo_partialInfo() throws Exception {
+ byte[] extras = new byte[20];
+ ByteBuffer buf = ByteBuffer.wrap(extras);
+ buf.order(ByteOrder.LITTLE_ENDIAN);
+ buf.putShort((short) 0x0001);
+ buf.putShort((short) 16);
+ buf.putLong(50);
+ buf.putLong(100);
+
+ ZipEntry ze = createZipEntry(extras, Zip64.MAX_ZIP_ENTRY_AND_ARCHIVE_SIZE,
+ Zip64.MAX_ZIP_ENTRY_AND_ARCHIVE_SIZE, ZipEntry.STORED, 300);
+
+ Zip64.parseZip64ExtendedInfo(ze, false /*fromCentralDirectory */);
+ assertEquals(50, ze.getSize());
+ assertEquals(100, ze.getCompressedSize());
+
+ ze = createZipEntry(extras, Zip64.MAX_ZIP_ENTRY_AND_ARCHIVE_SIZE,
+ Zip64.MAX_ZIP_ENTRY_AND_ARCHIVE_SIZE, ZipEntry.STORED, 300);
+ Zip64.parseZip64ExtendedInfo(ze, true /*fromCentralDirectory */);
+ assertEquals(50, ze.getSize());
+ assertEquals(100, ze.getCompressedSize());
+ }
+
+ public void testInsertZip64ExtendedInfo() throws Exception {
+ ZipEntry ze = createZipEntry(null, Zip64.MAX_ZIP_ENTRY_AND_ARCHIVE_SIZE + 300,
+ Zip64.MAX_ZIP_ENTRY_AND_ARCHIVE_SIZE + 500, ZipEntry.STORED, 300);
+ Zip64.insertZip64ExtendedInfoToExtras(ze);
+
+ assertNotNull(ze.getExtra());
+ ByteBuffer buf = ByteBuffer.wrap(ze.getExtra());
+ buf.order(ByteOrder.LITTLE_ENDIAN);
+ assertEquals(0x0001, buf.getShort());
+ assertEquals(24, buf.getShort());
+ assertEquals(Zip64.MAX_ZIP_ENTRY_AND_ARCHIVE_SIZE + 300, buf.getLong());
+ assertEquals(Zip64.MAX_ZIP_ENTRY_AND_ARCHIVE_SIZE + 500, buf.getLong());
+ }
+
+ private static ZipEntry createZipEntry(byte[] extras, long size, long compressedSize,
+ int compressionMethod, long headerOffset) {
+ return new ZipEntry("name", "comment", 42 /* crc */, compressedSize, size,
+ compressionMethod, 42 /* time */, 42 /* modDate */, extras, headerOffset,
+ 42 /* data offset */);
+ }
+}
diff --git a/luni/src/test/java/libcore/java/util/zip/ZipEntryTest.java b/luni/src/test/java/libcore/java/util/zip/ZipEntryTest.java
index 550ddfb..c7667b9 100644
--- a/luni/src/test/java/libcore/java/util/zip/ZipEntryTest.java
+++ b/luni/src/test/java/libcore/java/util/zip/ZipEntryTest.java
@@ -25,6 +25,7 @@ import java.util.Arrays;
import java.util.List;
import java.util.jar.JarEntry;
import java.util.zip.ZipEntry;
+import java.util.zip.ZipException;
import java.util.zip.ZipFile;
import java.util.zip.ZipInputStream;
import java.util.zip.ZipOutputStream;
@@ -132,6 +133,7 @@ public class ZipEntryTest extends junit.framework.TestCase {
File f = createTemporaryZipFile();
ZipOutputStream out = createZipOutputStream(f);
ZipEntry ze = new ZipEntry("x");
+ ze.setSize(0);
ze.setExtra(maxLengthExtra);
out.putNextEntry(ze);
out.closeEntry();
@@ -143,6 +145,25 @@ public class ZipEntryTest extends junit.framework.TestCase {
zipFile.close();
}
+ public void testMaxLengthExtra_zip64() throws Exception {
+ // Not quite the max length (65535), but large enough that there's no space
+ // for the zip64 extended info header.
+ byte[] maxLengthExtra = new byte[65530];
+
+ File f = createTemporaryZipFile();
+ ZipOutputStream out = new ZipOutputStream(new BufferedOutputStream(new FileOutputStream(f)),
+ true /* forceZip64 */);
+ ZipEntry ze = new ZipEntry("x");
+
+ ze.setExtra(maxLengthExtra);
+ try {
+ out.putNextEntry(ze);
+ fail();
+ } catch (ZipException expected) {
+ }
+ }
+
+
public void testTooLongComment() throws Exception {
String tooLongComment = makeString(65536, "z");
ZipEntry ze = new ZipEntry("x");
@@ -176,7 +197,17 @@ public class ZipEntryTest extends junit.framework.TestCase {
File f = createTemporaryZipFile();
ZipOutputStream out = createZipOutputStream(f);
+
+ // Regular (non zip64) format.
ZipEntry ze = new ZipEntry("x");
+ ze.setSize(0);
+ ze.setExtra(extra);
+ ze.setComment(comment);
+ out.putNextEntry(ze);
+ out.closeEntry();
+
+ // An entry without a length is assumed to be zip64.
+ ze = new ZipEntry("y");
ze.setExtra(extra);
ze.setComment(comment);
out.putNextEntry(ze);
@@ -188,6 +219,9 @@ public class ZipEntryTest extends junit.framework.TestCase {
try {
assertEquals(comment, zipFile.getEntry("x").getComment());
assertTrue(Arrays.equals(extra, zipFile.getEntry("x").getExtra()));
+
+ assertEquals(comment, zipFile.getEntry("y").getComment());
+ assertTrue(Arrays.equals(extra, zipFile.getEntry("y").getExtra()));
} finally {
zipFile.close();
}
diff --git a/luni/src/test/java/libcore/java/util/zip/ZipFileTest.java b/luni/src/test/java/libcore/java/util/zip/ZipFileTest.java
index a9ff56f..02210ac 100644
--- a/luni/src/test/java/libcore/java/util/zip/ZipFileTest.java
+++ b/luni/src/test/java/libcore/java/util/zip/ZipFileTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2010 The Android Open Source Project
+ * Copyright (C) 2015 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -11,497 +11,18 @@
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
- * limitations under the License.
+ * limitations under the License
*/
package libcore.java.util.zip;
-import java.io.BufferedOutputStream;
-import java.io.ByteArrayOutputStream;
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
import java.io.OutputStream;
-import java.nio.charset.Charset;
-import java.nio.charset.StandardCharsets;
-import java.util.ArrayList;
-import java.util.Enumeration;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Random;
-import java.util.Set;
-import java.util.zip.CRC32;
-import java.util.zip.ZipEntry;
-import java.util.zip.ZipException;
-import java.util.zip.ZipFile;
-import java.util.zip.ZipInputStream;
import java.util.zip.ZipOutputStream;
-import junit.framework.TestCase;
-import tests.support.resource.Support_Resources;
+public final class ZipFileTest extends AbstractZipFileTest {
-public final class ZipFileTest extends TestCase {
- /**
- * Exercise Inflater's ability to refill the zlib's input buffer. As of this
- * writing, this buffer's max size is 64KiB compressed bytes. We'll write a
- * full megabyte of uncompressed data, which should be sufficient to exhaust
- * the buffer. http://b/issue?id=2734751
- */
- public void testInflatingFilesRequiringZipRefill() throws IOException {
- int originalSize = 1024 * 1024;
- byte[] readBuffer = new byte[8192];
- ZipFile zipFile = new ZipFile(createZipFile(1, originalSize));
- for (Enumeration<? extends ZipEntry> e = zipFile.entries(); e.hasMoreElements(); ) {
- ZipEntry zipEntry = e.nextElement();
- assertTrue("This test needs >64 KiB of compressed data to exercise Inflater",
- zipEntry.getCompressedSize() > (64 * 1024));
- InputStream is = zipFile.getInputStream(zipEntry);
- while (is.read(readBuffer, 0, readBuffer.length) != -1) {}
- is.close();
- }
- zipFile.close();
- }
-
- private static void replaceBytes(byte[] buffer, byte[] original, byte[] replacement) {
- // Gotcha here: original and replacement must be the same length
- assertEquals(original.length, replacement.length);
- boolean found;
- for(int i=0; i < buffer.length - original.length; i++) {
- found = false;
- if (buffer[i] == original[0]) {
- found = true;
- for (int j=0; j < original.length; j++) {
- if (buffer[i+j] != original[j]) {
- found = false;
- break;
- }
- }
- }
- if (found) {
- for (int j=0; j < original.length; j++) {
- buffer[i+j] = replacement[j];
- }
- }
- }
- }
-
- private static void writeBytes(File f, byte[] bytes) throws IOException {
- FileOutputStream out = new FileOutputStream(f);
- out.write(bytes);
- out.close();
- }
-
- /**
- * Make sure we don't fail silently for duplicate entries.
- * b/8219321
- */
- public void testDuplicateEntries() throws Exception {
- String name1 = "test_file_name1";
- String name2 = "test_file_name2";
-
- // Create the good zip file.
- ByteArrayOutputStream baos = new ByteArrayOutputStream();
- ZipOutputStream out = new ZipOutputStream(baos);
- out.putNextEntry(new ZipEntry(name2));
- out.closeEntry();
- out.putNextEntry(new ZipEntry(name1));
- out.closeEntry();
- out.close();
-
- // Rewrite one of the filenames.
- byte[] buffer = baos.toByteArray();
- replaceBytes(buffer, name2.getBytes(), name1.getBytes());
-
- // Write the result to a file.
- File badZip = createTemporaryZipFile();
- writeBytes(badZip, buffer);
-
- // Check that we refuse to load the modified file.
- try {
- ZipFile bad = new ZipFile(badZip);
- fail();
- } catch (ZipException expected) {
- }
- }
-
- /**
- * Make sure the size used for stored zip entires is the uncompressed size.
- * b/10227498
- */
- public void testStoredEntrySize() throws Exception {
- ByteArrayOutputStream baos = new ByteArrayOutputStream();
- ZipOutputStream out = new ZipOutputStream(baos);
-
- // Set up a single stored entry.
- String name = "test_file";
- int expectedLength = 5;
- ZipEntry outEntry = new ZipEntry(name);
- byte[] buffer = new byte[expectedLength];
- outEntry.setMethod(ZipEntry.STORED);
- CRC32 crc = new CRC32();
- crc.update(buffer);
- outEntry.setCrc(crc.getValue());
- outEntry.setSize(buffer.length);
-
- out.putNextEntry(outEntry);
- out.write(buffer);
- out.closeEntry();
- out.close();
-
- // Write the result to a file.
- byte[] outBuffer = baos.toByteArray();
- File zipFile = createTemporaryZipFile();
- writeBytes(zipFile, outBuffer);
-
- ZipFile zip = new ZipFile(zipFile);
- // Set up the zip entry to have different compressed/uncompressed sizes.
- ZipEntry ze = zip.getEntry(name);
- ze.setCompressedSize(expectedLength - 1);
- // Read the contents of the stream and verify uncompressed size was used.
- InputStream stream = zip.getInputStream(ze);
- int count = 0;
- int read;
- while ((read = stream.read(buffer)) != -1) {
- count += read;
- }
-
- assertEquals(expectedLength, count);
- zip.close();
- }
-
- public void testInflatingStreamsRequiringZipRefill() throws IOException {
- int originalSize = 1024 * 1024;
- byte[] readBuffer = new byte[8192];
- ZipInputStream in = new ZipInputStream(new FileInputStream(createZipFile(1, originalSize)));
- while (in.getNextEntry() != null) {
- while (in.read(readBuffer, 0, readBuffer.length) != -1) {}
- }
- in.close();
- }
-
- public void testZipFileWithLotsOfEntries() throws IOException {
- int expectedEntryCount = 64*1024 - 1;
- File f = createZipFile(expectedEntryCount, 0);
- ZipFile zipFile = new ZipFile(f);
- int entryCount = 0;
- for (Enumeration<? extends ZipEntry> e = zipFile.entries(); e.hasMoreElements(); ) {
- ZipEntry zipEntry = e.nextElement();
- ++entryCount;
- }
- assertEquals(expectedEntryCount, entryCount);
- zipFile.close();
- }
-
- // http://code.google.com/p/android/issues/detail?id=36187
- public void testZipFileLargerThan2GiB() throws IOException {
- if (false) { // TODO: this test requires too much time and too much disk space!
- File f = createZipFile(1024, 3*1024*1024);
- ZipFile zipFile = new ZipFile(f);
- int entryCount = 0;
- for (Enumeration<? extends ZipEntry> e = zipFile.entries(); e.hasMoreElements(); ) {
- ZipEntry zipEntry = e.nextElement();
- ++entryCount;
- }
- assertEquals(1024, entryCount);
- zipFile.close();
- }
- }
-
- public void testZip64Support() throws IOException {
- try {
- createZipFile(64*1024, 0);
- fail(); // Make this test more like testHugeZipFile when we have Zip64 support.
- } catch (ZipException expected) {
- }
- }
-
- /**
- * Compresses the given number of files, each of the given size, into a .zip archive.
- */
- private File createZipFile(int entryCount, int entrySize) throws IOException {
- File result = createTemporaryZipFile();
-
- byte[] writeBuffer = new byte[8192];
- Random random = new Random();
-
- ZipOutputStream out = createZipOutputStream(result);
- try {
- for (int entry = 0; entry < entryCount; ++entry) {
- ZipEntry ze = new ZipEntry(Integer.toHexString(entry));
- out.putNextEntry(ze);
-
- for (int i = 0; i < entrySize; i += writeBuffer.length) {
- random.nextBytes(writeBuffer);
- int byteCount = Math.min(writeBuffer.length, entrySize - i);
- out.write(writeBuffer, 0, byteCount);
- }
-
- out.closeEntry();
- }
- } finally {
- out.close();
- }
- return result;
- }
-
- private File createTemporaryZipFile() throws IOException {
- File result = File.createTempFile("ZipFileTest", "zip");
- result.deleteOnExit();
- return result;
- }
-
- private ZipOutputStream createZipOutputStream(File f) throws IOException {
- return new ZipOutputStream(new BufferedOutputStream(new FileOutputStream(f)));
- }
-
- public void testSTORED() throws IOException {
- ZipOutputStream out = createZipOutputStream(createTemporaryZipFile());
- CRC32 crc = new CRC32();
-
- // Missing CRC, size, and compressed size => failure.
- try {
- ZipEntry ze = new ZipEntry("a");
- ze.setMethod(ZipEntry.STORED);
- out.putNextEntry(ze);
- fail();
- } catch (ZipException expected) {
- }
-
- // Missing CRC and compressed size => failure.
- try {
- ZipEntry ze = new ZipEntry("a");
- ze.setMethod(ZipEntry.STORED);
- ze.setSize(0);
- out.putNextEntry(ze);
- fail();
- } catch (ZipException expected) {
- }
-
- // Missing CRC and size => failure.
- try {
- ZipEntry ze = new ZipEntry("a");
- ze.setMethod(ZipEntry.STORED);
- ze.setSize(0);
- ze.setCompressedSize(0);
- out.putNextEntry(ze);
- fail();
- } catch (ZipException expected) {
- }
-
- // Missing size and compressed size => failure.
- try {
- ZipEntry ze = new ZipEntry("a");
- ze.setMethod(ZipEntry.STORED);
- ze.setCrc(crc.getValue());
- out.putNextEntry(ze);
- fail();
- } catch (ZipException expected) {
- }
-
- // Missing size is copied from compressed size.
- {
- ZipEntry ze = new ZipEntry("okay1");
- ze.setMethod(ZipEntry.STORED);
- ze.setCrc(crc.getValue());
-
- assertEquals(-1, ze.getSize());
- assertEquals(-1, ze.getCompressedSize());
-
- ze.setCompressedSize(0);
-
- assertEquals(-1, ze.getSize());
- assertEquals(0, ze.getCompressedSize());
-
- out.putNextEntry(ze);
-
- assertEquals(0, ze.getSize());
- assertEquals(0, ze.getCompressedSize());
- }
-
- // Missing compressed size is copied from size.
- {
- ZipEntry ze = new ZipEntry("okay2");
- ze.setMethod(ZipEntry.STORED);
- ze.setCrc(crc.getValue());
-
- assertEquals(-1, ze.getSize());
- assertEquals(-1, ze.getCompressedSize());
-
- ze.setSize(0);
-
- assertEquals(0, ze.getSize());
- assertEquals(-1, ze.getCompressedSize());
-
- out.putNextEntry(ze);
-
- assertEquals(0, ze.getSize());
- assertEquals(0, ze.getCompressedSize());
- }
-
- // Mismatched size and compressed size => failure.
- try {
- ZipEntry ze = new ZipEntry("a");
- ze.setMethod(ZipEntry.STORED);
- ze.setCrc(crc.getValue());
- ze.setCompressedSize(1);
- ze.setSize(0);
- out.putNextEntry(ze);
- fail();
- } catch (ZipException expected) {
- }
-
- // Everything present => success.
- ZipEntry ze = new ZipEntry("okay");
- ze.setMethod(ZipEntry.STORED);
- ze.setCrc(crc.getValue());
- ze.setSize(0);
- ze.setCompressedSize(0);
- out.putNextEntry(ze);
-
- out.close();
- }
-
- private String makeString(int count, String ch) {
- StringBuilder sb = new StringBuilder();
- for (int i = 0; i < count; ++i) {
- sb.append(ch);
- }
- return sb.toString();
- }
-
- public void testComments() throws Exception {
- String expectedFileComment = "1 \u0666 2";
- String expectedEntryComment = "a \u0666 b";
-
- File file = createTemporaryZipFile();
- ZipOutputStream out = createZipOutputStream(file);
-
- // Is file comment length checking done on bytes or characters? (Should be bytes.)
- out.setComment(null);
- out.setComment(makeString(0xffff, "a"));
- try {
- out.setComment(makeString(0xffff + 1, "a"));
- fail();
- } catch (IllegalArgumentException expected) {
- }
- try {
- out.setComment(makeString(0xffff, "\u0666"));
- fail();
- } catch (IllegalArgumentException expected) {
- }
-
- ZipEntry ze = new ZipEntry("a");
-
- // Is entry comment length checking done on bytes or characters? (Should be bytes.)
- ze.setComment(null);
- ze.setComment(makeString(0xffff, "a"));
- try {
- ze.setComment(makeString(0xffff + 1, "a"));
- fail();
- } catch (IllegalArgumentException expected) {
- }
- try {
- ze.setComment(makeString(0xffff, "\u0666"));
- fail();
- } catch (IllegalArgumentException expected) {
- }
-
- ze.setComment(expectedEntryComment);
- out.putNextEntry(ze);
- out.closeEntry();
-
- out.setComment(expectedFileComment);
- out.close();
-
- ZipFile zipFile = new ZipFile(file);
- assertEquals(expectedFileComment, zipFile.getComment());
- assertEquals(expectedEntryComment, zipFile.getEntry("a").getComment());
- zipFile.close();
- }
-
- public void test_getComment_unset() throws Exception {
- File file = createTemporaryZipFile();
- ZipOutputStream out = createZipOutputStream(file);
- ZipEntry ze = new ZipEntry("test entry");
- ze.setComment("per-entry comment");
- out.putNextEntry(ze);
- out.close();
-
- ZipFile zipFile = new ZipFile(file);
- assertEquals(null, zipFile.getComment());
- }
-
- // https://code.google.com/p/android/issues/detail?id=58465
- public void test_NUL_in_filename() throws Exception {
- File file = createTemporaryZipFile();
-
- // We allow creation of a ZipEntry whose name contains a NUL byte,
- // mainly because it's not likely to happen by accident and it's useful for testing.
- ZipOutputStream out = createZipOutputStream(file);
- out.putNextEntry(new ZipEntry("hello"));
- out.putNextEntry(new ZipEntry("hello\u0000"));
- out.close();
-
- // But you can't open a ZIP file containing such an entry, because we reject it
- // when we find it in the central directory.
- try {
- ZipFile zipFile = new ZipFile(file);
- fail();
- } catch (ZipException expected) {
- }
- }
-
- public void testCrc() throws IOException {
- ZipEntry ze = new ZipEntry("test");
- ze.setMethod(ZipEntry.STORED);
- ze.setSize(4);
-
- // setCrc takes a long, not an int, so -1 isn't a valid CRC32 (because it's 64 bits).
- try {
- ze.setCrc(-1);
- } catch (IllegalArgumentException expected) {
- }
-
- // You can set the CRC32 to 0xffffffff if you're slightly more careful though...
- ze.setCrc(0xffffffffL);
- assertEquals(0xffffffffL, ze.getCrc());
-
- // And it actually works, even though we use -1L to mean "no CRC set"...
- ZipOutputStream out = createZipOutputStream(createTemporaryZipFile());
- out.putNextEntry(ze);
- out.write(-1);
- out.write(-1);
- out.write(-1);
- out.write(-1);
- out.closeEntry();
- out.close();
- }
-
- /**
- * RI does not allow reading of an empty zip using a {@link ZipFile}.
- */
- public void testConstructorFailsWhenReadingEmptyZipArchive() throws IOException {
-
- File resources = Support_Resources.createTempFolder();
- File emptyZip = Support_Resources.copyFile(
- resources, "java/util/zip", "EmptyArchive.zip");
-
- try {
- // The following should fail with an exception but if it doesn't then we need to clean
- // up the resource so we need a reference to it.
- ZipFile zipFile = new ZipFile(emptyZip);
-
- // Clean up the resource.
- try {
- zipFile.close();
- } catch (Exception e) {
- // Ignore
- }
- fail();
- } catch (ZipException expected) {
- // expected
- }
+ @Override
+ protected ZipOutputStream createZipOutputStream(OutputStream wrapped) {
+ return new ZipOutputStream(wrapped);
}
}
diff --git a/luni/src/test/java/libcore/java/util/zip/ZipOutputStreamTest.java b/luni/src/test/java/libcore/java/util/zip/ZipOutputStreamTest.java
index e69f010..15600de 100644
--- a/luni/src/test/java/libcore/java/util/zip/ZipOutputStreamTest.java
+++ b/luni/src/test/java/libcore/java/util/zip/ZipOutputStreamTest.java
@@ -21,7 +21,6 @@ import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
-import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.Random;
import java.util.zip.ZipEntry;
diff --git a/luni/src/test/java/libcore/javax/crypto/CipherTest.java b/luni/src/test/java/libcore/javax/crypto/CipherTest.java
index c89886c..dd7d6e7 100644
--- a/luni/src/test/java/libcore/javax/crypto/CipherTest.java
+++ b/luni/src/test/java/libcore/javax/crypto/CipherTest.java
@@ -21,11 +21,13 @@ import java.io.ByteArrayOutputStream;
import java.io.PrintStream;
import java.math.BigInteger;
import java.nio.ByteBuffer;
+import java.nio.charset.StandardCharsets;
import java.security.AlgorithmParameters;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.Key;
import java.security.KeyFactory;
+import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.Provider;
@@ -45,6 +47,7 @@ import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
+import javax.crypto.AEADBadTagException;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
@@ -231,6 +234,10 @@ public final class CipherTest extends TestCase {
return algorithm.startsWith("PBE");
}
+ private static boolean isAEAD(String algorithm) {
+ return "GCM".equals(algorithm) || algorithm.contains("/GCM/");
+ }
+
private static boolean isStreamMode(String algorithm) {
return algorithm.contains("/CTR/") || algorithm.contains("/OFB")
|| algorithm.contains("/CFB");
@@ -295,10 +302,10 @@ public final class CipherTest extends TestCase {
setExpectedBlockSize("AES/ECB/PKCS5PADDING", 16);
setExpectedBlockSize("AES/ECB/PKCS7PADDING", 16);
setExpectedBlockSize("AES/ECB/NOPADDING", 16);
+ setExpectedBlockSize("AES/GCM/NOPADDING", 16);
setExpectedBlockSize("AES/OFB/PKCS5PADDING", 16);
setExpectedBlockSize("AES/OFB/PKCS7PADDING", 16);
setExpectedBlockSize("AES/OFB/NOPADDING", 16);
- setExpectedBlockSize("GCM", 16);
setExpectedBlockSize("PBEWITHMD5AND128BITAES-CBC-OPENSSL", 16);
setExpectedBlockSize("PBEWITHMD5AND192BITAES-CBC-OPENSSL", 16);
setExpectedBlockSize("PBEWITHMD5AND256BITAES-CBC-OPENSSL", 16);
@@ -453,9 +460,9 @@ public final class CipherTest extends TestCase {
setExpectedOutputSize("AES/CTS/PKCS7PADDING", Cipher.ENCRYPT_MODE, 16);
setExpectedOutputSize("AES/ECB/PKCS5PADDING", Cipher.ENCRYPT_MODE, 16);
setExpectedOutputSize("AES/ECB/PKCS7PADDING", Cipher.ENCRYPT_MODE, 16);
+ setExpectedOutputSize("AES/GCM/NOPADDING", Cipher.ENCRYPT_MODE, GCM_TAG_SIZE_BITS / 8);
setExpectedOutputSize("AES/OFB/PKCS5PADDING", Cipher.ENCRYPT_MODE, 16);
setExpectedOutputSize("AES/OFB/PKCS7PADDING", Cipher.ENCRYPT_MODE, 16);
- setExpectedOutputSize("GCM", Cipher.ENCRYPT_MODE, GCM_TAG_SIZE_BITS / 8);
setExpectedOutputSize("PBEWITHMD5AND128BITAES-CBC-OPENSSL", 16);
setExpectedOutputSize("PBEWITHMD5AND192BITAES-CBC-OPENSSL", 16);
setExpectedOutputSize("PBEWITHMD5AND256BITAES-CBC-OPENSSL", 16);
@@ -486,9 +493,9 @@ public final class CipherTest extends TestCase {
setExpectedOutputSize("AES/CTS/PKCS7PADDING", Cipher.DECRYPT_MODE, 0);
setExpectedOutputSize("AES/ECB/PKCS5PADDING", Cipher.DECRYPT_MODE, 0);
setExpectedOutputSize("AES/ECB/PKCS7PADDING", Cipher.DECRYPT_MODE, 0);
+ setExpectedOutputSize("AES/GCM/NOPADDING", Cipher.DECRYPT_MODE, 0);
setExpectedOutputSize("AES/OFB/PKCS5PADDING", Cipher.DECRYPT_MODE, 0);
setExpectedOutputSize("AES/OFB/PKCS7PADDING", Cipher.DECRYPT_MODE, 0);
- setExpectedOutputSize("GCM", Cipher.DECRYPT_MODE, 0);
setExpectedOutputSize("PBEWITHMD5AND128BITAES-CBC-OPENSSL", Cipher.DECRYPT_MODE, 0);
setExpectedOutputSize("PBEWITHMD5AND192BITAES-CBC-OPENSSL", Cipher.DECRYPT_MODE, 0);
setExpectedOutputSize("PBEWITHMD5AND256BITAES-CBC-OPENSSL", Cipher.DECRYPT_MODE, 0);
@@ -498,15 +505,8 @@ public final class CipherTest extends TestCase {
setExpectedOutputSize("PBEWITHSHAAND128BITAES-CBC-BC", Cipher.DECRYPT_MODE, 0);
setExpectedOutputSize("PBEWITHSHAAND192BITAES-CBC-BC", Cipher.DECRYPT_MODE, 0);
setExpectedOutputSize("PBEWITHSHAAND256BITAES-CBC-BC", Cipher.DECRYPT_MODE, 0);
- // AndroidOpenSSL returns the block size for the block ciphers
- setExpectedOutputSize("AES/CBC/PKCS5PADDING", Cipher.DECRYPT_MODE, "AndroidOpenSSL", 16);
- setExpectedOutputSize("AES/CBC/PKCS7PADDING", Cipher.DECRYPT_MODE, "AndroidOpenSSL", 16);
- setExpectedOutputSize("AES/ECB/PKCS5PADDING", Cipher.DECRYPT_MODE, "AndroidOpenSSL", 16);
- setExpectedOutputSize("AES/ECB/PKCS7PADDING", Cipher.DECRYPT_MODE, "AndroidOpenSSL", 16);
- setExpectedOutputSize("DESEDE/CBC/PKCS5PADDING", Cipher.DECRYPT_MODE, "AndroidOpenSSL", 8);
- setExpectedOutputSize("DESEDE/CBC/PKCS7PADDING", Cipher.DECRYPT_MODE, "AndroidOpenSSL", 8);
- setExpectedOutputSize("DESEDE/ECB/PKCS5PADDING", Cipher.DECRYPT_MODE, "AndroidOpenSSL", 8);
- setExpectedOutputSize("DESEDE/ECB/PKCS7PADDING", Cipher.DECRYPT_MODE, "AndroidOpenSSL", 8);
+ setExpectedOutputSize("DESEDE/CBC/PKCS5PADDING", Cipher.DECRYPT_MODE, "AndroidOpenSSL", 0);
+ setExpectedOutputSize("DESEDE/CBC/PKCS7PADDING", Cipher.DECRYPT_MODE, "AndroidOpenSSL", 0);
if (StandardNames.IS_RI) {
setExpectedOutputSize("AESWRAP", Cipher.WRAP_MODE, 8);
@@ -750,8 +750,8 @@ public final class CipherTest extends TestCase {
new SecureRandom().nextBytes(salt);
return new PBEParameterSpec(salt, 1024);
}
- if (algorithm.equals("GCM")) {
- final byte[] iv = new byte[8];
+ if (algorithm.equals("AES/GCM/NOPADDING")) {
+ final byte[] iv = new byte[12];
new SecureRandom().nextBytes(iv);
return new GCMParameterSpec(GCM_TAG_SIZE_BITS, iv);
}
@@ -791,7 +791,7 @@ public final class CipherTest extends TestCase {
}
byte[] iv = encryptCipher.getIV();
if (iv != null) {
- if ("GCM".equals(algorithm)) {
+ if ("AES/GCM/NOPADDING".equals(algorithm)) {
return new GCMParameterSpec(GCM_TAG_SIZE_BITS, iv);
}
return new IvParameterSpec(iv);
@@ -847,6 +847,24 @@ public final class CipherTest extends TestCase {
}
}
+ public void testCipher_getInstance_DoesNotSupportKeyClass_Success() throws Exception {
+ Provider mockProvider = new MockProvider("MockProvider") {
+ public void setup() {
+ put("Cipher.FOO", MockCipherSpi.AllKeyTypes.class.getName());
+ put("Cipher.FOO SupportedKeyClasses", "None");
+ }
+ };
+
+ Security.addProvider(mockProvider);
+ try {
+ Cipher c = Cipher.getInstance("FOO", mockProvider);
+ c.init(Cipher.ENCRYPT_MODE, new MockKey());
+ assertEquals(mockProvider, c.getProvider());
+ } finally {
+ Security.removeProvider(mockProvider.getName());
+ }
+ }
+
public void testCipher_getInstance_SuppliedProviderNotRegistered_MultipartTransform_Success()
throws Exception {
Provider mockProvider = new MockProvider("MockProvider") {
@@ -970,14 +988,130 @@ public final class CipherTest extends TestCase {
Security.addProvider(mockProviderInvalid);
try {
- Cipher.getInstance("FOO");
- fail("Should not find any matching providers");
- } catch (NoSuchAlgorithmException expected) {
+ Cipher c = Cipher.getInstance("FOO");
+ c.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(new byte[16], "FOO"));
+ fail("Should not find any matching providers; found: " + c);
+ } catch (ClassCastException expected) {
} finally {
Security.removeProvider(mockProviderInvalid.getName());
}
}
+ public void testCipher_init_CallsInitWithParams_AlgorithmParameterSpec() throws Exception {
+ Provider mockProviderRejects = new MockProvider("MockProviderRejects") {
+ public void setup() {
+ put("Cipher.FOO",
+ MockCipherSpi.MustInitWithAlgorithmParameterSpec_RejectsAll.class.getName());
+ put("Cipher.FOO SupportedKeyClasses", MockKey.class.getName());
+ }
+ };
+ Provider mockProviderAccepts = new MockProvider("MockProviderAccepts") {
+ public void setup() {
+ put("Cipher.FOO", MockCipherSpi.AllKeyTypes.class.getName());
+ put("Cipher.FOO SupportedKeyClasses", MockKey.class.getName());
+ }
+ };
+
+ Security.addProvider(mockProviderRejects);
+ Security.addProvider(mockProviderAccepts);
+ try {
+ Cipher c = Cipher.getInstance("FOO");
+ c.init(Cipher.ENCRYPT_MODE, new MockKey(), new IvParameterSpec(new byte[12]));
+ assertEquals(mockProviderAccepts, c.getProvider());
+ } finally {
+ Security.removeProvider(mockProviderRejects.getName());
+ Security.removeProvider(mockProviderAccepts.getName());
+ }
+ }
+
+ public void testCipher_init_CallsInitWithParams_AlgorithmParameters() throws Exception {
+ Provider mockProviderRejects = new MockProvider("MockProviderRejects") {
+ public void setup() {
+ put("Cipher.FOO",
+ MockCipherSpi.MustInitWithAlgorithmParameters_RejectsAll.class.getName());
+ put("Cipher.FOO SupportedKeyClasses", MockKey.class.getName());
+ }
+ };
+ Provider mockProviderAccepts = new MockProvider("MockProviderAccepts") {
+ public void setup() {
+ put("Cipher.FOO", MockCipherSpi.AllKeyTypes.class.getName());
+ put("Cipher.FOO SupportedKeyClasses", MockKey.class.getName());
+ }
+ };
+
+ Security.addProvider(mockProviderRejects);
+ Security.addProvider(mockProviderAccepts);
+ try {
+ Cipher c = Cipher.getInstance("FOO");
+ c.init(Cipher.ENCRYPT_MODE, new MockKey(), AlgorithmParameters.getInstance("AES"));
+ assertEquals(mockProviderAccepts, c.getProvider());
+ } finally {
+ Security.removeProvider(mockProviderRejects.getName());
+ Security.removeProvider(mockProviderAccepts.getName());
+ }
+ }
+
+ public void testCipher_init_CallsInitIgnoresRuntimeException() throws Exception {
+ Provider mockProviderRejects = new MockProvider("MockProviderRejects") {
+ public void setup() {
+ put("Cipher.FOO",
+ MockCipherSpi.MustInitWithAlgorithmParameters_ThrowsNull.class.getName());
+ put("Cipher.FOO SupportedKeyClasses", MockKey.class.getName());
+ }
+ };
+ Provider mockProviderAccepts = new MockProvider("MockProviderAccepts") {
+ public void setup() {
+ put("Cipher.FOO", MockCipherSpi.AllKeyTypes.class.getName());
+ put("Cipher.FOO SupportedKeyClasses", MockKey.class.getName());
+ }
+ };
+
+ Security.addProvider(mockProviderRejects);
+ Security.addProvider(mockProviderAccepts);
+ try {
+ Cipher c = Cipher.getInstance("FOO");
+ c.init(Cipher.ENCRYPT_MODE, new MockKey(), AlgorithmParameters.getInstance("AES"));
+ assertEquals(mockProviderAccepts, c.getProvider());
+ } finally {
+ Security.removeProvider(mockProviderRejects.getName());
+ Security.removeProvider(mockProviderAccepts.getName());
+ }
+ }
+
+ public void testCipher_init_CallsInitWithMode() throws Exception {
+ Provider mockProviderOnlyEncrypt = new MockProvider("MockProviderOnlyEncrypt") {
+ public void setup() {
+ put("Cipher.FOO", MockCipherSpi.MustInitForEncryptModeOrRejects.class.getName());
+ put("Cipher.FOO SupportedKeyClasses", MockKey.class.getName());
+ }
+ };
+ Provider mockProviderAcceptsAll = new MockProvider("MockProviderAcceptsAll") {
+ public void setup() {
+ put("Cipher.FOO", MockCipherSpi.AllKeyTypes.class.getName());
+ put("Cipher.FOO SupportedKeyClasses", MockKey.class.getName());
+ }
+ };
+
+ Security.addProvider(mockProviderOnlyEncrypt);
+ Security.addProvider(mockProviderAcceptsAll);
+ try {
+ {
+ Cipher c = Cipher.getInstance("FOO");
+ c.init(Cipher.DECRYPT_MODE, new MockKey(), AlgorithmParameters.getInstance("AES"));
+ assertEquals(mockProviderAcceptsAll, c.getProvider());
+ }
+
+ {
+ Cipher c = Cipher.getInstance("FOO");
+ c.init(Cipher.ENCRYPT_MODE, new MockKey(), AlgorithmParameters.getInstance("AES"));
+ assertEquals(mockProviderOnlyEncrypt, c.getProvider());
+ }
+ } finally {
+ Security.removeProvider(mockProviderOnlyEncrypt.getName());
+ Security.removeProvider(mockProviderAcceptsAll.getName());
+ }
+ }
+
public void test_getInstance() throws Exception {
final ByteArrayOutputStream errBuffer = new ByteArrayOutputStream();
PrintStream out = new PrintStream(errBuffer);
@@ -1125,9 +1259,9 @@ public final class CipherTest extends TestCase {
c.init(encryptMode, encryptKey, encryptSpec);
assertEquals(cipherID + " getBlockSize() encryptMode",
- getExpectedBlockSize(algorithm, encryptMode, providerName), c.getBlockSize());
- assertEquals(cipherID + " getOutputSize(0) encryptMode",
- getExpectedOutputSize(algorithm, encryptMode, providerName), c.getOutputSize(0));
+ getExpectedBlockSize(algorithm, encryptMode, providerName), c.getBlockSize());
+ assertTrue(cipherID + " getOutputSize(0) encryptMode",
+ getExpectedOutputSize(algorithm, encryptMode, providerName) <= c.getOutputSize(0));
if ((algorithm.endsWith("/PKCS5PADDING") || algorithm.endsWith("/PKCS7PADDING"))
&& isStreamMode(algorithm)) {
assertEquals(getExpectedOutputSize(algorithm, encryptMode, providerName),
@@ -1136,6 +1270,9 @@ public final class CipherTest extends TestCase {
final AlgorithmParameterSpec decryptSpec = getDecryptAlgorithmParameterSpec(encryptSpec, c);
int decryptMode = getDecryptMode(algorithm);
+
+ test_Cipher_init_Decrypt_NullParameters(c, decryptMode, encryptKey, decryptSpec != null);
+
c.init(decryptMode, encryptKey, decryptSpec);
assertEquals(cipherID + " getBlockSize() decryptMode",
getExpectedBlockSize(algorithm, decryptMode, providerName), c.getBlockSize());
@@ -1188,7 +1325,7 @@ public final class CipherTest extends TestCase {
// Test wrapping a key. Every cipher should be able to wrap. Except those that can't.
/* Bouncycastle is broken for wrapping because getIV() fails. */
if (isSupportedForWrapping(algorithm)
- && !algorithm.equals("GCM") && !providerName.equals("BC")) {
+ && !algorithm.equals("AES/GCM/NOPADDING") && !providerName.equals("BC")) {
// Generate a small SecretKey for AES.
KeyGenerator kg = KeyGenerator.getInstance("AES");
kg.init(128);
@@ -1212,16 +1349,28 @@ public final class CipherTest extends TestCase {
if (!isOnlyWrappingAlgorithm(algorithm)) {
c.init(Cipher.ENCRYPT_MODE, encryptKey, encryptSpec);
+ if (isAEAD(algorithm)) {
+ c.updateAAD(new byte[24]);
+ }
byte[] cipherText = c.doFinal(getActualPlainText(algorithm));
+ if (isAEAD(algorithm)) {
+ c.updateAAD(new byte[24]);
+ }
byte[] cipherText2 = c.doFinal(getActualPlainText(algorithm));
assertEquals(cipherID,
Arrays.toString(cipherText),
Arrays.toString(cipherText2));
c.init(Cipher.DECRYPT_MODE, getDecryptKey(algorithm), decryptSpec);
+ if (isAEAD(algorithm)) {
+ c.updateAAD(new byte[24]);
+ }
byte[] decryptedPlainText = c.doFinal(cipherText);
assertEquals(cipherID,
Arrays.toString(getExpectedPlainText(algorithm, providerName)),
Arrays.toString(decryptedPlainText));
+ if (isAEAD(algorithm)) {
+ c.updateAAD(new byte[24]);
+ }
byte[] decryptedPlainText2 = c.doFinal(cipherText);
assertEquals(cipherID,
Arrays.toString(decryptedPlainText),
@@ -1268,6 +1417,53 @@ public final class CipherTest extends TestCase {
}
}
+ private void test_Cipher_init_Decrypt_NullParameters(Cipher c, int decryptMode, Key encryptKey,
+ boolean needsParameters) throws Exception {
+ try {
+ c.init(decryptMode, encryptKey, (AlgorithmParameterSpec) null);
+ if (needsParameters) {
+ fail("Should throw InvalidAlgorithmParameterException with null parameters");
+ }
+ } catch (InvalidAlgorithmParameterException e) {
+ if (!needsParameters) {
+ throw e;
+ }
+ }
+
+ try {
+ c.init(decryptMode, encryptKey, (AlgorithmParameterSpec) null, (SecureRandom) null);
+ if (needsParameters) {
+ fail("Should throw InvalidAlgorithmParameterException with null parameters");
+ }
+ } catch (InvalidAlgorithmParameterException e) {
+ if (!needsParameters) {
+ throw e;
+ }
+ }
+
+ try {
+ c.init(decryptMode, encryptKey, (AlgorithmParameters) null);
+ if (needsParameters) {
+ fail("Should throw InvalidAlgorithmParameterException with null parameters");
+ }
+ } catch (InvalidAlgorithmParameterException e) {
+ if (!needsParameters) {
+ throw e;
+ }
+ }
+
+ try {
+ c.init(decryptMode, encryptKey, (AlgorithmParameters) null, (SecureRandom) null);
+ if (needsParameters) {
+ fail("Should throw InvalidAlgorithmParameterException with null parameters");
+ }
+ } catch (InvalidAlgorithmParameterException e) {
+ if (!needsParameters) {
+ throw e;
+ }
+ }
+ }
+
public void testInputPKCS1Padding() throws Exception {
for (String provider : RSA_PROVIDERS) {
testInputPKCS1Padding(provider);
@@ -1293,11 +1489,22 @@ public final class CipherTest extends TestCase {
Cipher encryptCipher = Cipher.getInstance("RSA/ECB/NoPadding", provider);
encryptCipher.init(Cipher.ENCRYPT_MODE, encryptKey);
byte[] cipherText = encryptCipher.doFinal(prePaddedPlainText);
+ encryptCipher.update(prePaddedPlainText);
+ encryptCipher.init(Cipher.ENCRYPT_MODE, encryptKey);
+ byte[] cipherText2 = encryptCipher.doFinal(prePaddedPlainText);
+ assertEquals(Arrays.toString(cipherText),
+ Arrays.toString(cipherText2));
+
Cipher decryptCipher = Cipher.getInstance("RSA/ECB/PKCS1Padding", provider);
decryptCipher.init(Cipher.DECRYPT_MODE, decryptKey);
byte[] plainText = decryptCipher.doFinal(cipherText);
assertEquals(Arrays.toString(ORIGINAL_PLAIN_TEXT),
Arrays.toString(plainText));
+ decryptCipher.update(prePaddedPlainText);
+ decryptCipher.init(Cipher.DECRYPT_MODE, decryptKey);
+ byte[] plainText2 = decryptCipher.doFinal(cipherText);
+ assertEquals(Arrays.toString(plainText),
+ Arrays.toString(plainText2));
}
public void testOutputPKCS1Padding() throws Exception {
@@ -2423,6 +2630,80 @@ public final class CipherTest extends TestCase {
};
/*
+ * Taken from BoringSSL test vectors.
+ */
+ private static final byte[] AES_128_GCM_TestVector_1_Key = new byte[] {
+ (byte) 0xca, (byte) 0xbd, (byte) 0xcf, (byte) 0x54, (byte) 0x1a, (byte) 0xeb,
+ (byte) 0xf9, (byte) 0x17, (byte) 0xba, (byte) 0xc0, (byte) 0x19, (byte) 0xf1,
+ (byte) 0x39, (byte) 0x25, (byte) 0xd2, (byte) 0x67,
+ };
+
+ /*
+ * Taken from BoringSSL test vectors.
+ */
+ private static final byte[] AES_128_GCM_TestVector_1_IV = new byte[] {
+ (byte) 0x2c, (byte) 0x34, (byte) 0xc0, (byte) 0x0c, (byte) 0x42, (byte) 0xda,
+ (byte) 0xe3, (byte) 0x82, (byte) 0x27, (byte) 0x9d, (byte) 0x79, (byte) 0x74,
+ };
+
+ /*
+ * Taken from BoringSSL test vectors.
+ */
+ private static final byte[] AES_128_GCM_TestVector_1_AAD = new byte[] {
+ (byte) 0xdd, (byte) 0x10, (byte) 0xe3, (byte) 0x71, (byte) 0xb2, (byte) 0x2e,
+ (byte) 0x15, (byte) 0x67, (byte) 0x1c, (byte) 0x31, (byte) 0xaf, (byte) 0xee,
+ (byte) 0x55, (byte) 0x2b, (byte) 0xf1, (byte) 0xde, (byte) 0xa0, (byte) 0x7c,
+ (byte) 0xbb, (byte) 0xf6, (byte) 0x85, (byte) 0xe2, (byte) 0xca, (byte) 0xa0,
+ (byte) 0xe0, (byte) 0x36, (byte) 0x37, (byte) 0x16, (byte) 0xa2, (byte) 0x76,
+ (byte) 0xe1, (byte) 0x20, (byte) 0xc6, (byte) 0xc0, (byte) 0xeb, (byte) 0x4a,
+ (byte) 0xcb, (byte) 0x1a, (byte) 0x4d, (byte) 0x1b, (byte) 0xa7, (byte) 0x3f,
+ (byte) 0xde, (byte) 0x66, (byte) 0x15, (byte) 0xf7, (byte) 0x08, (byte) 0xaa,
+ (byte) 0xa4, (byte) 0x6b, (byte) 0xc7, (byte) 0x6c, (byte) 0x7f, (byte) 0xf3,
+ (byte) 0x45, (byte) 0xa4, (byte) 0xf7, (byte) 0x6b, (byte) 0xda, (byte) 0x11,
+ (byte) 0x7f, (byte) 0xe5, (byte) 0x6f, (byte) 0x0d, (byte) 0xc9, (byte) 0xb9,
+ (byte) 0x39, (byte) 0x04, (byte) 0x0d, (byte) 0xdd,
+ };
+
+ /*
+ * Taken from BoringSSL test vectors.
+ */
+ private static final byte[] AES_128_GCM_TestVector_1_Plaintext = new byte[] {
+ (byte) 0x88, (byte) 0xcc, (byte) 0x1e, (byte) 0x07, (byte) 0xdf, (byte) 0xde,
+ (byte) 0x8e, (byte) 0x08, (byte) 0x08, (byte) 0x2e, (byte) 0x67, (byte) 0x66,
+ (byte) 0xe0, (byte) 0xa8, (byte) 0x81, (byte) 0x03, (byte) 0x38, (byte) 0x47,
+ (byte) 0x42, (byte) 0xaf, (byte) 0x37, (byte) 0x8d, (byte) 0x7b, (byte) 0x6b,
+ (byte) 0x8a, (byte) 0x87, (byte) 0xfc, (byte) 0xe0, (byte) 0x36, (byte) 0xaf,
+ (byte) 0x74, (byte) 0x41, (byte) 0xc1, (byte) 0x39, (byte) 0x61, (byte) 0xc2,
+ (byte) 0x5a, (byte) 0xfe, (byte) 0xa7, (byte) 0xf6, (byte) 0xe5, (byte) 0x61,
+ (byte) 0x93, (byte) 0xf5, (byte) 0x4b, (byte) 0xee, (byte) 0x00, (byte) 0x11,
+ (byte) 0xcb, (byte) 0x78, (byte) 0x64, (byte) 0x2c, (byte) 0x3a, (byte) 0xb9,
+ (byte) 0xe6, (byte) 0xd5, (byte) 0xb2, (byte) 0xe3, (byte) 0x58, (byte) 0x33,
+ (byte) 0xec, (byte) 0x16, (byte) 0xcd, (byte) 0x35, (byte) 0x55, (byte) 0x15,
+ (byte) 0xaf, (byte) 0x1a, (byte) 0x19, (byte) 0x0f,
+ };
+
+ /*
+ * Taken from BoringSSL test vectors.
+ */
+ private static final byte[] AES_128_GCM_TestVector_1_Encrypted = new byte[] {
+ (byte) 0x04, (byte) 0x94, (byte) 0x53, (byte) 0xba, (byte) 0xf1, (byte) 0x57,
+ (byte) 0x87, (byte) 0x87, (byte) 0xd6, (byte) 0x8e, (byte) 0xd5, (byte) 0x47,
+ (byte) 0x87, (byte) 0x26, (byte) 0xc0, (byte) 0xb8, (byte) 0xa6, (byte) 0x36,
+ (byte) 0x33, (byte) 0x7a, (byte) 0x0b, (byte) 0x8a, (byte) 0x82, (byte) 0xb8,
+ (byte) 0x68, (byte) 0x36, (byte) 0xf9, (byte) 0x1c, (byte) 0xde, (byte) 0x25,
+ (byte) 0xe6, (byte) 0xe4, (byte) 0x4c, (byte) 0x34, (byte) 0x59, (byte) 0x40,
+ (byte) 0xe8, (byte) 0x19, (byte) 0xa0, (byte) 0xc5, (byte) 0x05, (byte) 0x75,
+ (byte) 0x1e, (byte) 0x60, (byte) 0x3c, (byte) 0xb8, (byte) 0xf8, (byte) 0xc4,
+ (byte) 0xfe, (byte) 0x98, (byte) 0x71, (byte) 0x91, (byte) 0x85, (byte) 0x56,
+ (byte) 0x27, (byte) 0x94, (byte) 0xa1, (byte) 0x85, (byte) 0xe5, (byte) 0xde,
+ (byte) 0xc4, (byte) 0x15, (byte) 0xc8, (byte) 0x1f, (byte) 0x2f, (byte) 0x16,
+ (byte) 0x2c, (byte) 0xdc, (byte) 0xd6, (byte) 0x50, (byte) 0xdc, (byte) 0xe7,
+ (byte) 0x19, (byte) 0x87, (byte) 0x28, (byte) 0xbf, (byte) 0xc1, (byte) 0xb5,
+ (byte) 0xf9, (byte) 0x49, (byte) 0xb9, (byte) 0xb5, (byte) 0x37, (byte) 0x41,
+ (byte) 0x99, (byte) 0xc6,
+ };
+
+ /*
* Test key generation:
* openssl rand -hex 16
* echo 'ceaa31952dfd3d0f5af4b2042ba06094' | sed 's/\(..\)/(byte) 0x\1, /g'
@@ -2491,17 +2772,20 @@ public final class CipherTest extends TestCase {
public final byte[] iv;
+ public final byte[] aad;
+
public final byte[] plaintext;
public final byte[] ciphertext;
public final byte[] plaintextPadded;
- public CipherTestParam(String transformation, byte[] key, byte[] iv, byte[] plaintext,
- byte[] plaintextPadded, byte[] ciphertext) {
- this.transformation = transformation;
+ public CipherTestParam(String transformation, byte[] key, byte[] iv, byte[] aad,
+ byte[] plaintext, byte[] plaintextPadded, byte[] ciphertext) {
+ this.transformation = transformation.toUpperCase(Locale.ROOT);
this.key = key;
this.iv = iv;
+ this.aad = aad;
this.plaintext = plaintext;
this.plaintextPadded = plaintextPadded;
this.ciphertext = ciphertext;
@@ -2512,23 +2796,34 @@ public final class CipherTest extends TestCase {
static {
CIPHER_TEST_PARAMS.add(new CipherTestParam("AES/ECB/PKCS5Padding", AES_128_KEY,
null,
+ null,
AES_128_ECB_PKCS5Padding_TestVector_1_Plaintext,
AES_128_ECB_PKCS5Padding_TestVector_1_Plaintext_Padded,
AES_128_ECB_PKCS5Padding_TestVector_1_Encrypted));
// PKCS#5 is assumed to be equivalent to PKCS#7 -- same test vectors are thus used for both.
CIPHER_TEST_PARAMS.add(new CipherTestParam("AES/ECB/PKCS7Padding", AES_128_KEY,
null,
+ null,
AES_128_ECB_PKCS5Padding_TestVector_1_Plaintext,
AES_128_ECB_PKCS5Padding_TestVector_1_Plaintext_Padded,
AES_128_ECB_PKCS5Padding_TestVector_1_Encrypted));
+ CIPHER_TEST_PARAMS.add(new CipherTestParam("AES/GCM/NOPADDING",
+ AES_128_GCM_TestVector_1_Key,
+ AES_128_GCM_TestVector_1_IV,
+ AES_128_GCM_TestVector_1_AAD,
+ AES_128_GCM_TestVector_1_Plaintext,
+ AES_128_GCM_TestVector_1_Plaintext,
+ AES_128_GCM_TestVector_1_Encrypted));
if (IS_UNLIMITED) {
CIPHER_TEST_PARAMS.add(new CipherTestParam("AES/CBC/PKCS5Padding", AES_256_KEY,
AES_256_CBC_PKCS5Padding_TestVector_1_IV,
+ null,
AES_256_CBC_PKCS5Padding_TestVector_1_Plaintext,
AES_256_CBC_PKCS5Padding_TestVector_1_Plaintext_Padded,
AES_256_CBC_PKCS5Padding_TestVector_1_Ciphertext));
CIPHER_TEST_PARAMS.add(new CipherTestParam("AES/CBC/PKCS7Padding", AES_256_KEY,
AES_256_CBC_PKCS5Padding_TestVector_1_IV,
+ null,
AES_256_CBC_PKCS5Padding_TestVector_1_Plaintext,
AES_256_CBC_PKCS5Padding_TestVector_1_Plaintext_Padded,
AES_256_CBC_PKCS5Padding_TestVector_1_Ciphertext));
@@ -2564,62 +2859,98 @@ public final class CipherTest extends TestCase {
private void checkCipher(CipherTestParam p, String provider) throws Exception {
SecretKey key = new SecretKeySpec(p.key, "AES");
Cipher c = Cipher.getInstance(p.transformation, provider);
+
AlgorithmParameterSpec spec = null;
if (p.iv != null) {
- spec = new IvParameterSpec(p.iv);
+ if (isAEAD(p.transformation)) {
+ spec = new GCMParameterSpec((p.ciphertext.length - p.plaintext.length) * 8, p.iv);
+ } else {
+ spec = new IvParameterSpec(p.iv);
+ }
}
+
c.init(Cipher.ENCRYPT_MODE, key, spec);
+ if (p.aad != null) {
+ c.updateAAD(p.aad);
+ }
final byte[] actualCiphertext = c.doFinal(p.plaintext);
- assertEquals(Arrays.toString(p.ciphertext), Arrays.toString(actualCiphertext));
+ assertEquals(p.transformation + " " + provider, Arrays.toString(p.ciphertext),
+ Arrays.toString(actualCiphertext));
+ c = Cipher.getInstance(p.transformation, provider);
+ c.init(Cipher.ENCRYPT_MODE, key, spec);
byte[] emptyCipherText = c.doFinal();
assertNotNull(emptyCipherText);
c.init(Cipher.DECRYPT_MODE, key, spec);
- try {
- c.updateAAD(new byte[8]);
- fail("Cipher should not support AAD");
- } catch (UnsupportedOperationException expected) {
+ if (!isAEAD(p.transformation)) {
+ try {
+ c.updateAAD(new byte[8]);
+ fail("Cipher should not support AAD");
+ } catch (UnsupportedOperationException | IllegalStateException expected) {
+ }
}
- byte[] emptyPlainText = c.doFinal(emptyCipherText);
- assertEquals(Arrays.toString(new byte[0]), Arrays.toString(emptyPlainText));
+ try {
+ byte[] emptyPlainText = c.doFinal(emptyCipherText);
+ assertEquals(Arrays.toString(new byte[0]), Arrays.toString(emptyPlainText));
+ } catch (AEADBadTagException e) {
+ if (!"AndroidOpenSSL".equals(provider) || !isAEAD(p.transformation)) {
+ throw e;
+ }
+ }
// empty decrypt
{
- if (StandardNames.IS_RI) {
+ if (!isAEAD(p.transformation)
+ && (StandardNames.IS_RI || provider.equals("AndroidOpenSSL"))) {
assertEquals(Arrays.toString(new byte[0]),
Arrays.toString(c.doFinal()));
c.update(new byte[0]);
assertEquals(Arrays.toString(new byte[0]),
Arrays.toString(c.doFinal()));
- } else if (provider.equals("BC")) {
+ } else if (provider.equals("BC") || isAEAD(p.transformation)) {
try {
c.doFinal();
fail();
- } catch (IllegalBlockSizeException expected) {
+ } catch (IllegalBlockSizeException maybe) {
+ if (isAEAD(p.transformation)) {
+ throw maybe;
+ }
+ } catch (AEADBadTagException maybe) {
+ if (!isAEAD(p.transformation)) {
+ throw maybe;
+ }
}
try {
c.update(new byte[0]);
c.doFinal();
fail();
- } catch (IllegalBlockSizeException expected) {
+ } catch (IllegalBlockSizeException maybe) {
+ if (isAEAD(p.transformation)) {
+ throw maybe;
+ }
+ } catch (AEADBadTagException maybe) {
+ if (!isAEAD(p.transformation)) {
+ throw maybe;
+ }
}
- } else if (provider.equals("AndroidOpenSSL")) {
- assertNull(c.doFinal());
-
- c.update(new byte[0]);
- assertNull(c.doFinal());
} else {
throw new AssertionError("Define your behavior here for " + provider);
}
}
+ // Cipher might be in unspecified state from failures above.
+ c.init(Cipher.DECRYPT_MODE, key, spec);
+
// .doFinal(input)
{
+ if (p.aad != null) {
+ c.updateAAD(p.aad);
+ }
final byte[] actualPlaintext = c.doFinal(p.ciphertext);
assertEquals(Arrays.toString(p.plaintext), Arrays.toString(actualPlaintext));
}
@@ -2629,6 +2960,12 @@ public final class CipherTest extends TestCase {
final byte[] largerThanCiphertext = new byte[p.ciphertext.length + 5];
System.arraycopy(p.ciphertext, 0, largerThanCiphertext, 5, p.ciphertext.length);
+ if (p.aad != null) {
+ final byte[] largerThanAad = new byte[p.aad.length + 100];
+ System.arraycopy(p.aad, 0, largerThanAad, 50, p.aad.length);
+ c.updateAAD(largerThanAad, 50, p.aad.length);
+ }
+
final byte[] actualPlaintext = new byte[c.getOutputSize(p.ciphertext.length)];
assertEquals(p.plaintext.length,
c.doFinal(largerThanCiphertext, 5, p.ciphertext.length, actualPlaintext));
@@ -2641,6 +2978,12 @@ public final class CipherTest extends TestCase {
final byte[] largerThanCiphertext = new byte[p.ciphertext.length + 10];
System.arraycopy(p.ciphertext, 0, largerThanCiphertext, 5, p.ciphertext.length);
+ if (p.aad != null) {
+ final byte[] largerThanAad = new byte[p.aad.length + 2];
+ System.arraycopy(p.aad, 0, largerThanAad, 2, p.aad.length);
+ c.updateAAD(largerThanAad, 2, p.aad.length);
+ }
+
final byte[] actualPlaintext = new byte[c.getOutputSize(p.ciphertext.length) + 2];
assertEquals(p.plaintext.length,
c.doFinal(largerThanCiphertext, 5, p.ciphertext.length, actualPlaintext, 1));
@@ -2648,13 +2991,18 @@ public final class CipherTest extends TestCase {
Arrays.toString(Arrays.copyOfRange(actualPlaintext, 1, p.plaintext.length + 1)));
}
- Cipher cNoPad = Cipher.getInstance(
- getCipherTransformationWithNoPadding(p.transformation), provider);
- cNoPad.init(Cipher.DECRYPT_MODE, key, spec);
+ if (!p.transformation.endsWith("NOPADDING")) {
+ Cipher cNoPad = Cipher.getInstance(
+ getCipherTransformationWithNoPadding(p.transformation), provider);
+ cNoPad.init(Cipher.DECRYPT_MODE, key, spec);
- final byte[] actualPlaintextPadded = cNoPad.doFinal(p.ciphertext);
- assertEquals(provider + ":" + cNoPad.getAlgorithm(), Arrays.toString(p.plaintextPadded),
- Arrays.toString(actualPlaintextPadded));
+ if (p.aad != null) {
+ c.updateAAD(p.aad);
+ }
+ final byte[] actualPlaintextPadded = cNoPad.doFinal(p.ciphertext);
+ assertEquals(provider + ":" + cNoPad.getAlgorithm(),
+ Arrays.toString(p.plaintextPadded), Arrays.toString(actualPlaintextPadded));
+ }
// Test wrapping a key. Every cipher should be able to wrap.
{
@@ -2664,6 +3012,7 @@ public final class CipherTest extends TestCase {
SecretKey sk = kg.generateKey();
// Wrap it
+ c = Cipher.getInstance(p.transformation, provider);
c.init(Cipher.WRAP_MODE, key, spec);
byte[] cipherText = c.wrap(sk);
@@ -2770,6 +3119,27 @@ public final class CipherTest extends TestCase {
fail("should not be able to call updateAAD with too large length");
} catch (IllegalArgumentException expected) {
}
+
+ try {
+ c.updateAAD(new byte[8]);
+ fail("should not be able to call updateAAD on non-AEAD cipher");
+ } catch (UnsupportedOperationException | IllegalStateException expected) {
+ }
+ }
+
+ public void testCipher_updateAAD_AfterInit_WithGcm_Success() throws Exception {
+ Cipher c = Cipher.getInstance("AES/GCM/NoPadding");
+ c.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(new byte[128 / 8], "AES"));
+ c.updateAAD(new byte[8]);
+ c.updateAAD(new byte[8]);
+ }
+
+ public void testCipher_updateAAD_AfterUpdate_WithGcm_Sucess() throws Exception {
+ Cipher c = Cipher.getInstance("AES/GCM/NoPadding");
+ c.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(new byte[128 / 8], "AES"));
+ c.updateAAD(new byte[8]);
+ c.update(new byte[8]);
+ c.updateAAD(new byte[8]);
}
public void testCipher_ShortBlock_Failure() throws Exception {
@@ -2797,7 +3167,24 @@ public final class CipherTest extends TestCase {
}
}
+ public void testCipher_Update_WithZeroLengthInput_ReturnsNull() throws Exception {
+ SecretKey key = new SecretKeySpec(AES_128_KEY, "AES");
+ Cipher c = Cipher.getInstance("AES/ECB/NoPadding");
+ c.init(Cipher.ENCRYPT_MODE, key);
+ assertNull(c.update(new byte[0]));
+ assertNull(c.update(new byte[c.getBlockSize() * 2], 0, 0));
+
+ // Try with non-zero offset just in case the implementation mixes up offset and inputLen
+ assertNull(c.update(new byte[c.getBlockSize() * 2], 16, 0));
+ }
+
private void checkCipher_ShortBlock_Failure(CipherTestParam p, String provider) throws Exception {
+ // Do not try to test ciphers with no padding already.
+ String noPaddingTransform = getCipherTransformationWithNoPadding(p.transformation);
+ if (p.transformation.equals(noPaddingTransform)) {
+ return;
+ }
+
SecretKey key = new SecretKeySpec(p.key, "AES");
Cipher c = Cipher.getInstance(
getCipherTransformationWithNoPadding(p.transformation), provider);
@@ -2805,12 +3192,14 @@ public final class CipherTest extends TestCase {
return;
}
- c.init(Cipher.ENCRYPT_MODE, key);
- try {
- c.doFinal(new byte[] { 0x01, 0x02, 0x03 });
- fail("Should throw IllegalBlockSizeException on wrong-sized block; provider="
- + provider);
- } catch (IllegalBlockSizeException expected) {
+ if (!p.transformation.endsWith("NOPADDING")) {
+ c.init(Cipher.ENCRYPT_MODE, key);
+ try {
+ c.doFinal(new byte[] { 0x01, 0x02, 0x03 });
+ fail("Should throw IllegalBlockSizeException on wrong-sized block; transform="
+ + p.transformation + " provider=" + provider);
+ } catch (IllegalBlockSizeException expected) {
+ }
}
}
@@ -2985,4 +3374,145 @@ public final class CipherTest extends TestCase {
}
}
}
+
+ /**
+ * Several exceptions can be thrown by init. Check that in this case we throw the right one,
+ * as the error could fall under the umbrella of other exceptions.
+ * http://b/18987633
+ */
+ public void testCipher_init_DoesNotSupportKeyClass_throwsInvalidKeyException()
+ throws Exception {
+ Provider mockProvider = new MockProvider("MockProvider") {
+ public void setup() {
+ put("Cipher.FOO", MockCipherSpi.AllKeyTypes.class.getName());
+ put("Cipher.FOO SupportedKeyClasses", "none");
+ }
+ };
+
+ Security.addProvider(mockProvider);
+ try {
+ Cipher c = Cipher.getInstance("FOO");
+ c.init(Cipher.DECRYPT_MODE, new MockKey());
+ fail("Expected InvalidKeyException");
+ } catch (InvalidKeyException expected) {
+ } finally {
+ Security.removeProvider(mockProvider.getName());
+ }
+ }
+
+ /*
+ * When in decrypt mode and using padding, the buffer shouldn't necessarily have room for an
+ * extra block when using padding.
+ * http://b/19186852
+ */
+ public void testDecryptBufferMultipleBlockSize_mustNotThrowException() throws Exception {
+ String testString = "Hello, World!";
+ byte[] testKey = "0123456789012345".getBytes(StandardCharsets.US_ASCII);
+ String testedCipher = "AES/ECB/PKCS7Padding";
+
+ Cipher encCipher = Cipher.getInstance(testedCipher);
+ encCipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(testKey, "AES"));
+ byte[] plainBuffer = testString.getBytes(StandardCharsets.US_ASCII);
+ byte[] encryptedBuffer = new byte[16];
+ int encryptedLength = encCipher.doFinal(
+ plainBuffer, 0, plainBuffer.length, encryptedBuffer);
+ assertEquals(16, encryptedLength);
+
+ Cipher cipher = Cipher.getInstance(testedCipher);
+ cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(testKey, "AES"));
+ // Must not throw exception.
+ int unencryptedBytes = cipher.doFinal(
+ encryptedBuffer, 0, encryptedBuffer.length, encryptedBuffer);
+ assertEquals(testString,
+ new String(encryptedBuffer, 0, unencryptedBytes, StandardCharsets.US_ASCII));
+ }
+
+ /**
+ * When using padding in decrypt mode, ensure that empty buffers decode to empty strings
+ * (no padding needed for the empty buffer).
+ * http://b/19186852
+ */
+ public void testDecryptBufferZeroSize_mustDecodeToEmptyString() throws Exception {
+ String[] androidOpenSSLCiphers = { "AES/CBC/PKCS5PADDING", "AES/CBC/PKCS7PADDING",
+ "AES/ECB/PKCS5PADDING", "AES/ECB/PKCS7PADDING", "DESEDE/CBC/PKCS5PADDING",
+ "DESEDE/CBC/PKCS7PADDING" };
+ for (String c : androidOpenSSLCiphers) {
+ Cipher cipher = Cipher.getInstance(c);
+ if (c.contains("/CBC/")) {
+ cipher.init(Cipher.DECRYPT_MODE,
+ new SecretKeySpec("0123456789012345".getBytes(StandardCharsets.US_ASCII),
+ (c.startsWith("AES/")) ? "AES" : "DESEDE"),
+ new IvParameterSpec(
+ ("01234567" + ((c.startsWith("AES/")) ? "89012345" : ""))
+ .getBytes(StandardCharsets.US_ASCII)));
+ } else {
+ cipher.init(Cipher.DECRYPT_MODE,
+ new SecretKeySpec("0123456789012345".getBytes(StandardCharsets.US_ASCII),
+ (c.startsWith("AES/")) ? "AES" : "DESEDE"));
+ }
+
+ byte[] buffer = new byte[0];
+ int bytesProduced = cipher.doFinal(buffer, 0, buffer.length, buffer);
+ assertEquals("", new String(buffer, 0, bytesProduced, StandardCharsets.US_ASCII));
+ }
+ }
+
+ /**
+ * If a provider rejects a key for "Cipher/Mode/Padding"", there might be another that
+ * accepts the key for "Cipher". Don't throw InvalidKeyException when trying the first one.
+ * http://b/22208820
+ */
+ public void testCipher_init_tryAllCombinationsBeforeThrowingInvalidKey()
+ throws Exception {
+ Provider mockProvider = new MockProvider("MockProvider") {
+ public void setup() {
+ put("Cipher.FOO/FOO/FOO", MockCipherSpi.AllKeyTypes.class.getName());
+ put("Cipher.FOO/FOO/FOO SupportedKeyClasses", "none");
+ }
+ };
+
+ Provider mockProvider2 = new MockProvider("MockProvider2") {
+ public void setup() {
+ put("Cipher.FOO", MockCipherSpi.AllKeyTypes.class.getName());
+ }
+ };
+
+ Security.addProvider(mockProvider);
+
+ try {
+ try {
+ // The provider installed doesn't accept the key.
+ Cipher c = Cipher.getInstance("FOO/FOO/FOO");
+ c.init(Cipher.DECRYPT_MODE, new MockKey());
+ fail("Expected InvalidKeyException");
+ } catch (InvalidKeyException expected) {
+ }
+
+ Security.addProvider(mockProvider2);
+
+ try {
+ // The new provider accepts "FOO" with this key. Use it despite the other provider
+ // accepts "FOO/FOO/FOO" but doesn't accept the key.
+ Cipher c = Cipher.getInstance("FOO/FOO/FOO");
+ c.init(Cipher.DECRYPT_MODE, new MockKey());
+ assertEquals("MockProvider2", c.getProvider().getName());
+ } finally {
+ Security.removeProvider(mockProvider2.getName());
+ }
+ } finally {
+ Security.removeProvider(mockProvider.getName());
+ }
+ }
+
+ /**
+ * Check that RSA with OAEPPadding is supported.
+ * http://b/22208820
+ */
+ public void test_RSA_OAEPPadding() throws Exception {
+ KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA");
+ keyGen.initialize(1024, SecureRandom.getInstance("SHA1PRNG"));
+ Cipher cipher = Cipher.getInstance("RSA/NONE/OAEPPadding");
+ cipher.init(Cipher.ENCRYPT_MODE, keyGen.generateKeyPair().getPublic());
+ cipher.doFinal(new byte[] {1,2,3,4});
+ }
}
diff --git a/luni/src/test/java/libcore/javax/crypto/ECDHKeyAgreementTest.java b/luni/src/test/java/libcore/javax/crypto/ECDHKeyAgreementTest.java
index cabe5c9..cc29640 100644
--- a/luni/src/test/java/libcore/javax/crypto/ECDHKeyAgreementTest.java
+++ b/luni/src/test/java/libcore/javax/crypto/ECDHKeyAgreementTest.java
@@ -38,7 +38,9 @@ import java.security.spec.ECGenParameterSpec;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Arrays;
+import java.util.ArrayList;
import java.util.Comparator;
+import java.util.List;
import javax.crypto.KeyAgreement;
import javax.crypto.SecretKey;
@@ -374,8 +376,8 @@ public class ECDHKeyAgreementTest extends TestCase {
if (providers == null) {
return new Provider[0];
}
- // Sort providers by name to guarantee non-determinism in the order in which providers are
- // used in the tests.
+ // Sort providers by name to guarantee deterministic order in which providers are used in
+ // the tests.
return sortByName(providers);
}
@@ -384,8 +386,21 @@ public class ECDHKeyAgreementTest extends TestCase {
if (providers == null) {
return new Provider[0];
}
- // Sort providers by name to guarantee non-determinism in the order in which providers are
- // used in the tests.
+
+ // Do not test AndroidKeyStore's KeyFactory. It only handles Android Keystore-backed keys.
+ // It's OKish not to test AndroidKeyStore's KeyFactory here because it's tested by
+ // cts/tests/test/keystore.
+ List<Provider> filteredProvidersList = new ArrayList<Provider>(providers.length);
+ for (Provider provider : providers) {
+ if ("AndroidKeyStore".equals(provider.getName())) {
+ continue;
+ }
+ filteredProvidersList.add(provider);
+ }
+ providers = filteredProvidersList.toArray(new Provider[filteredProvidersList.size()]);
+
+ // Sort providers by name to guarantee deterministic order in which providers are used in
+ // the tests.
return sortByName(providers);
}
diff --git a/luni/src/test/java/libcore/javax/crypto/KeyAgreementTest.java b/luni/src/test/java/libcore/javax/crypto/KeyAgreementTest.java
new file mode 100644
index 0000000..9281b43
--- /dev/null
+++ b/luni/src/test/java/libcore/javax/crypto/KeyAgreementTest.java
@@ -0,0 +1,95 @@
+/*
+ * Copyright 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package libcore.javax.crypto;
+
+import java.security.InvalidKeyException;
+import java.security.Provider;
+import java.security.Security;
+
+import javax.crypto.KeyAgreement;
+
+import junit.framework.TestCase;
+
+public class KeyAgreementTest extends TestCase {
+ private static abstract class MockProvider extends Provider {
+ public MockProvider(String name) {
+ super(name, 1.0, "Mock provider used for testing");
+ setup();
+ }
+
+ public abstract void setup();
+ }
+
+ public void testKeyAgreement_getInstance_SuppliedProviderNotRegistered_Success()
+ throws Exception {
+ Provider mockProvider = new MockProvider("MockProvider") {
+ public void setup() {
+ put("KeyAgreement.FOO", MockKeyAgreementSpi.AllKeyTypes.class.getName());
+ }
+ };
+
+ {
+ KeyAgreement c = KeyAgreement.getInstance("FOO", mockProvider);
+ c.init(new MockKey());
+ assertEquals(mockProvider, c.getProvider());
+ }
+ }
+
+ public void testKeyAgreement_getInstance_DoesNotSupportKeyClass_Success()
+ throws Exception {
+ Provider mockProvider = new MockProvider("MockProvider") {
+ public void setup() {
+ put("KeyAgreement.FOO", MockKeyAgreementSpi.AllKeyTypes.class.getName());
+ put("KeyAgreement.FOO SupportedKeyClasses", "none");
+ }
+ };
+
+ Security.addProvider(mockProvider);
+ try {
+ KeyAgreement c = KeyAgreement.getInstance("FOO", mockProvider);
+ c.init(new MockKey());
+ assertEquals(mockProvider, c.getProvider());
+ } finally {
+ Security.removeProvider(mockProvider.getName());
+ }
+ }
+
+ /**
+ * Several exceptions can be thrown by init. Check that in this case we throw the right one,
+ * as the error could fall under the umbrella of other exceptions.
+ * http://b/18987633
+ */
+ public void testKeyAgreement_init_DoesNotSupportKeyClass_throwsInvalidKeyException()
+ throws Exception {
+ Provider mockProvider = new MockProvider("MockProvider") {
+ public void setup() {
+ put("KeyAgreement.FOO", MockKeyAgreementSpi.AllKeyTypes.class.getName());
+ put("KeyAgreement.FOO SupportedKeyClasses", "none");
+ }
+ };
+
+ Security.addProvider(mockProvider);
+ try {
+ KeyAgreement c = KeyAgreement.getInstance("FOO");
+ c.init(new MockKey());
+ fail("Expected InvalidKeyException");
+ } catch (InvalidKeyException expected) {
+ } finally {
+ Security.removeProvider(mockProvider.getName());
+ }
+ }
+}
diff --git a/luni/src/test/java/libcore/javax/crypto/KeyGeneratorTest.java b/luni/src/test/java/libcore/javax/crypto/KeyGeneratorTest.java
index 8bbd548..5763562 100644
--- a/luni/src/test/java/libcore/javax/crypto/KeyGeneratorTest.java
+++ b/luni/src/test/java/libcore/javax/crypto/KeyGeneratorTest.java
@@ -44,6 +44,15 @@ public class KeyGeneratorTest extends TestCase {
if (!type.equals("KeyGenerator")) {
continue;
}
+
+ // Do not test AndroidKeyStore's KeyGenerator. It cannot be initialized without
+ // providing AndroidKeyStore-specific algorithm parameters.
+ // It's OKish not to test AndroidKeyStore's KeyGenerator here because it's tested
+ // by cts/tests/test/keystore.
+ if ("AndroidKeyStore".equals(provider.getName())) {
+ continue;
+ }
+
String algorithm = service.getAlgorithm();
try {
// KeyGenerator.getInstance(String)
diff --git a/luni/src/test/java/libcore/javax/crypto/MacTest.java b/luni/src/test/java/libcore/javax/crypto/MacTest.java
new file mode 100644
index 0000000..314a564
--- /dev/null
+++ b/luni/src/test/java/libcore/javax/crypto/MacTest.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package libcore.javax.crypto;
+
+import junit.framework.TestCase;
+
+import java.security.InvalidKeyException;
+import java.security.Provider;
+import java.security.Security;
+
+import javax.crypto.Mac;
+
+public class MacTest extends TestCase {
+ private static abstract class MockProvider extends Provider {
+ public MockProvider(String name) {
+ super(name, 1.0, "Mock provider used for testing");
+ setup();
+ }
+
+ public abstract void setup();
+ }
+
+ /**
+ * Several exceptions can be thrown by init. Check that in this case we throw the right one,
+ * as the error could fall under the umbrella of other exceptions.
+ * http://b/18987633
+ */
+ public void testMac_init_DoesNotSupportKeyClass_throwsInvalidKeyException()
+ throws Exception {
+ Provider mockProvider = new MockProvider("MockProvider") {
+ public void setup() {
+ put("Mac.FOO", MockMacSpi.AllKeyTypes.class.getName());
+ put("Mac.FOO SupportedKeyClasses", "none");
+
+ }
+ };
+
+ Security.addProvider(mockProvider);
+ try {
+ Mac c = Mac.getInstance("FOO");
+ c.init(new MockKey());
+ fail("Expected InvalidKeyException");
+ } catch (InvalidKeyException expected) {
+ } finally {
+ Security.removeProvider(mockProvider.getName());
+ }
+ }
+}
diff --git a/luni/src/test/java/libcore/javax/crypto/MockCipherSpi.java b/luni/src/test/java/libcore/javax/crypto/MockCipherSpi.java
index 6742cf3..c1b1bd2 100644
--- a/luni/src/test/java/libcore/javax/crypto/MockCipherSpi.java
+++ b/luni/src/test/java/libcore/javax/crypto/MockCipherSpi.java
@@ -25,6 +25,7 @@ import java.security.SecureRandom;
import java.security.spec.AlgorithmParameterSpec;
import javax.crypto.BadPaddingException;
+import javax.crypto.Cipher;
import javax.crypto.CipherSpi;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
@@ -56,6 +57,92 @@ public class MockCipherSpi extends CipherSpi {
public static class AllKeyTypes extends MockCipherSpi {
}
+ public static class MustInitWithAlgorithmParameterSpec_RejectsAll extends MockCipherSpi {
+ @Override
+ protected void engineInit(int opmode, Key key, SecureRandom random)
+ throws InvalidKeyException {
+ throw new AssertionError("Must have AlgorithmParameterSpec");
+ }
+
+ @Override
+ protected void engineInit(int opmode, Key key, AlgorithmParameterSpec params,
+ SecureRandom random) throws InvalidKeyException, InvalidAlgorithmParameterException {
+ throw new InvalidAlgorithmParameterException("expected rejection");
+ }
+
+ @Override
+ protected void engineInit(int opmode, Key key, AlgorithmParameters params,
+ SecureRandom random) throws InvalidKeyException, InvalidAlgorithmParameterException {
+ throw new AssertionError("Must have AlgorithmParameterSpec");
+ }
+ }
+
+ public static class MustInitWithAlgorithmParameters_RejectsAll extends MockCipherSpi {
+ @Override
+ protected void engineInit(int opmode, Key key, SecureRandom random)
+ throws InvalidKeyException {
+ throw new AssertionError("Must have AlgorithmParameterSpec");
+ }
+
+ @Override
+ protected void engineInit(int opmode, Key key, AlgorithmParameterSpec params,
+ SecureRandom random) throws InvalidKeyException, InvalidAlgorithmParameterException {
+ throw new AssertionError("Must have AlgorithmParameterSpec");
+ }
+
+ @Override
+ protected void engineInit(int opmode, Key key, AlgorithmParameters params,
+ SecureRandom random) throws InvalidKeyException, InvalidAlgorithmParameterException {
+ throw new InvalidAlgorithmParameterException("expected rejection");
+ }
+ }
+
+ public static class MustInitWithAlgorithmParameters_ThrowsNull extends MockCipherSpi {
+ @Override
+ protected void engineInit(int opmode, Key key, SecureRandom random)
+ throws InvalidKeyException {
+ throw new NullPointerException("expected rejection");
+ }
+
+ @Override
+ protected void engineInit(int opmode, Key key, AlgorithmParameterSpec params,
+ SecureRandom random) throws InvalidKeyException, InvalidAlgorithmParameterException {
+ throw new NullPointerException("expected rejection");
+ }
+
+ @Override
+ protected void engineInit(int opmode, Key key, AlgorithmParameters params,
+ SecureRandom random) throws InvalidKeyException, InvalidAlgorithmParameterException {
+ throw new NullPointerException("expected rejection");
+ }
+ }
+
+ public static class MustInitForEncryptModeOrRejects extends MockCipherSpi {
+ @Override
+ protected void engineInit(int opmode, Key key, SecureRandom random)
+ throws InvalidKeyException {
+ if (opmode != Cipher.ENCRYPT_MODE) {
+ throw new InvalidKeyException("expected rejection");
+ }
+ }
+
+ @Override
+ protected void engineInit(int opmode, Key key, AlgorithmParameterSpec params,
+ SecureRandom random) throws InvalidKeyException, InvalidAlgorithmParameterException {
+ if (opmode != Cipher.ENCRYPT_MODE) {
+ throw new InvalidKeyException("expected rejection");
+ }
+ }
+
+ @Override
+ protected void engineInit(int opmode, Key key, AlgorithmParameters params,
+ SecureRandom random) throws InvalidKeyException, InvalidAlgorithmParameterException {
+ if (opmode != Cipher.ENCRYPT_MODE) {
+ throw new InvalidKeyException("expected rejection");
+ }
+ }
+ }
+
public void checkKeyType(Key key) throws InvalidKeyException {
}
diff --git a/luni/src/test/java/libcore/javax/crypto/MockKey.java b/luni/src/test/java/libcore/javax/crypto/MockKey.java
index 248e2de..1c758f3 100644
--- a/luni/src/test/java/libcore/javax/crypto/MockKey.java
+++ b/luni/src/test/java/libcore/javax/crypto/MockKey.java
@@ -25,7 +25,7 @@ import java.security.Key;
public class MockKey implements Key {
@Override
public String getAlgorithm() {
- throw new UnsupportedOperationException("not implemented");
+ return "MOCK";
}
@Override
diff --git a/luni/src/test/java/libcore/javax/crypto/MockKeyAgreementSpi.java b/luni/src/test/java/libcore/javax/crypto/MockKeyAgreementSpi.java
new file mode 100644
index 0000000..574dbeb
--- /dev/null
+++ b/luni/src/test/java/libcore/javax/crypto/MockKeyAgreementSpi.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package libcore.javax.crypto;
+
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidKeyException;
+import java.security.Key;
+import java.security.NoSuchAlgorithmException;
+import java.security.SecureRandom;
+import java.security.spec.AlgorithmParameterSpec;
+import javax.crypto.KeyAgreementSpi;
+import javax.crypto.SecretKey;
+import javax.crypto.ShortBufferException;
+
+/**
+ * Mock KeyAgreementSpi used by {@link KeyAgreementTest}.
+ */
+public class MockKeyAgreementSpi extends KeyAgreementSpi {
+ public static class SpecificKeyTypes extends MockKeyAgreementSpi {
+ @Override
+ public void checkKeyType(Key key) throws InvalidKeyException {
+ if (!(key instanceof MockKey)) {
+ throw new InvalidKeyException("Must be MockKey!");
+ }
+ }
+ }
+
+ public static class SpecificKeyTypes2 extends MockKeyAgreementSpi {
+ @Override
+ public void checkKeyType(Key key) throws InvalidKeyException {
+ System.err.println("Checking key of type " + key.getClass().getName());
+ if (!(key instanceof MockKey2)) {
+ throw new InvalidKeyException("Must be MockKey2!");
+ }
+ }
+ }
+
+ public static class AllKeyTypes extends MockKeyAgreementSpi {
+ }
+
+ public void checkKeyType(Key key) throws InvalidKeyException {
+ }
+
+ @Override
+ protected Key engineDoPhase(Key key, boolean lastPhase) throws InvalidKeyException,
+ IllegalStateException {
+ throw new UnsupportedOperationException("not implemented");
+ }
+
+ @Override
+ protected byte[] engineGenerateSecret() throws IllegalStateException {
+ throw new UnsupportedOperationException("not implemented");
+ }
+
+ @Override
+ protected int engineGenerateSecret(byte[] sharedSecret, int offset)
+ throws IllegalStateException, ShortBufferException {
+ throw new UnsupportedOperationException("not implemented");
+ }
+
+ @Override
+ protected SecretKey engineGenerateSecret(String algorithm) throws IllegalStateException,
+ NoSuchAlgorithmException, InvalidKeyException {
+ throw new UnsupportedOperationException("not implemented");
+ }
+
+ @Override
+ protected void engineInit(Key key, SecureRandom random) throws InvalidKeyException {
+ checkKeyType(key);
+ }
+
+ @Override
+ protected void engineInit(Key key, AlgorithmParameterSpec params, SecureRandom random)
+ throws InvalidKeyException, InvalidAlgorithmParameterException {
+ checkKeyType(key);
+ }
+}
diff --git a/luni/src/test/java/libcore/javax/crypto/MockMacSpi.java b/luni/src/test/java/libcore/javax/crypto/MockMacSpi.java
new file mode 100644
index 0000000..0edeba7
--- /dev/null
+++ b/luni/src/test/java/libcore/javax/crypto/MockMacSpi.java
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package libcore.javax.crypto;
+
+import java.security.AlgorithmParameters;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidKeyException;
+import java.security.Key;
+import java.security.NoSuchAlgorithmException;
+import java.security.SecureRandom;
+import java.security.spec.AlgorithmParameterSpec;
+
+import javax.crypto.BadPaddingException;
+import javax.crypto.MacSpi;
+import javax.crypto.IllegalBlockSizeException;
+import javax.crypto.NoSuchPaddingException;
+import javax.crypto.ShortBufferException;
+
+/**
+ * Mock CipherSpi used by {@link libcore.javax.crypto.CipherTest}.
+ */
+public class MockMacSpi extends MacSpi {
+ public static class SpecificKeyTypes extends MockMacSpi {
+ @Override
+ public void checkKeyType(Key key) throws InvalidKeyException {
+ if (!(key instanceof MockKey)) {
+ throw new InvalidKeyException("Must be MockKey!");
+ }
+ }
+ }
+
+ public static class SpecificKeyTypes2 extends MockMacSpi {
+ @Override
+ public void checkKeyType(Key key) throws InvalidKeyException {
+ System.err.println("Checking key of type " + key.getClass().getName());
+ if (!(key instanceof MockKey2)) {
+ throw new InvalidKeyException("Must be MockKey2!");
+ }
+ }
+ }
+
+ public static class AllKeyTypes extends MockMacSpi {
+ }
+
+ public void checkKeyType(Key key) throws InvalidKeyException {
+ }
+
+ @Override
+ protected int engineGetMacLength() {
+ throw new UnsupportedOperationException("not implemented");
+ }
+
+ @Override
+ protected void engineInit(Key key, AlgorithmParameterSpec params)
+ throws InvalidKeyException, InvalidAlgorithmParameterException {
+ throw new UnsupportedOperationException("not implemented");
+ }
+
+ @Override
+ protected void engineUpdate(byte input) {
+ throw new UnsupportedOperationException("not implemented");
+ }
+
+ @Override
+ protected void engineUpdate(byte[] input, int inputOffset, int inputLen) {
+ throw new UnsupportedOperationException("not implemented");
+ }
+
+ @Override
+ protected byte[] engineDoFinal() {
+ throw new UnsupportedOperationException("not implemented");
+ }
+
+ @Override
+ protected void engineReset() {
+ throw new UnsupportedOperationException("not implemented");
+ }
+}
diff --git a/luni/src/test/java/libcore/javax/net/ssl/DefaultHostnameVerifierTest.java b/luni/src/test/java/libcore/javax/net/ssl/DefaultHostnameVerifierTest.java
index feecebe..07ecd12 100644
--- a/luni/src/test/java/libcore/javax/net/ssl/DefaultHostnameVerifierTest.java
+++ b/luni/src/test/java/libcore/javax/net/ssl/DefaultHostnameVerifierTest.java
@@ -22,6 +22,7 @@ import java.math.BigInteger;
import java.nio.charset.StandardCharsets;
import java.security.Principal;
import java.security.PublicKey;
+import java.security.cert.Certificate;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
@@ -30,21 +31,32 @@ import java.util.Date;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
-import javax.net.ssl.DefaultHostnameVerifier;
+import javax.net.ssl.HostnameVerifier;
+import javax.net.ssl.HttpsURLConnection;
+import javax.net.ssl.SSLPeerUnverifiedException;
+import javax.net.ssl.SSLSession;
+import javax.net.ssl.SSLSessionContext;
import javax.security.auth.x500.X500Principal;
import junit.framework.TestCase;
+/**
+ * Tests for the platform-default {@link HostnameVerifier} as provided by
+ * {@link HttpsURLConnection#getDefaultHostnameVerifier()}.
+ */
public final class DefaultHostnameVerifierTest extends TestCase {
private static final int ALT_UNKNOWN = 0;
private static final int ALT_DNS_NAME = 2;
private static final int ALT_IPA_NAME = 7;
- private final DefaultHostnameVerifier verifier = new DefaultHostnameVerifier();
+ private final HostnameVerifier verifier = HttpsURLConnection.getDefaultHostnameVerifier();
public void testVerify() {
- assertTrue(verifier.verify("imap.g.com", new StubX509Certificate("cn=imap.g.com")));
- assertFalse(verifier.verify("imap.g.com", new StubX509Certificate("cn=imap2.g.com")));
- assertFalse(verifier.verify("imap.g.com", new StubX509Certificate("cn=sub.imap.g.com")));
+ assertTrue(verifyWithServerCertificate(
+ "imap.g.com", new StubX509Certificate("cn=imap.g.com")));
+ assertFalse(verifyWithServerCertificate(
+ "imap.g.com", new StubX509Certificate("cn=imap2.g.com")));
+ assertFalse(verifyWithServerCertificate(
+ "imap.g.com", new StubX509Certificate("cn=sub.imap.g.com")));
}
/**
@@ -52,32 +64,33 @@ public final class DefaultHostnameVerifierTest extends TestCase {
* be used as the identity and the CN should be ignored.
*/
public void testSubjectAltNameAndCn() {
- assertFalse(verifier.verify("imap.g.com", new StubX509Certificate("")
- .addSubjectAlternativeName(ALT_DNS_NAME, "a.y.com")));
- assertFalse(verifier.verify("imap.g.com", new StubX509Certificate("cn=imap.g.com")
+ assertFalse(verifyWithServerCertificate("imap.g.com", new StubX509Certificate("")
.addSubjectAlternativeName(ALT_DNS_NAME, "a.y.com")));
- assertTrue(verifier.verify("imap.g.com", new StubX509Certificate("")
+ assertFalse(
+ verifyWithServerCertificate("imap.g.com", new StubX509Certificate("cn=imap.g.com")
+ .addSubjectAlternativeName(ALT_DNS_NAME, "a.y.com")));
+ assertTrue(verifyWithServerCertificate("imap.g.com", new StubX509Certificate("")
.addSubjectAlternativeName(ALT_DNS_NAME, "imap.g.com")));
}
public void testSubjectAltNameWithWildcard() {
- assertTrue(verifier.verify("imap.g.com", new StubX509Certificate("")
+ assertTrue(verifyWithServerCertificate("imap.g.com", new StubX509Certificate("")
.addSubjectAlternativeName(ALT_DNS_NAME, "*.g.com")));
}
public void testSubjectAltNameWithIpAddress() {
- assertTrue(verifier.verify("1.2.3.4", new StubX509Certificate("")
+ assertTrue(verifyWithServerCertificate("1.2.3.4", new StubX509Certificate("")
.addSubjectAlternativeName(ALT_IPA_NAME, "1.2.3.4")));
- assertFalse(verifier.verify("1.2.3.5", new StubX509Certificate("")
+ assertFalse(verifyWithServerCertificate("1.2.3.5", new StubX509Certificate("")
.addSubjectAlternativeName(ALT_IPA_NAME, "1.2.3.4")));
- assertTrue(verifier.verify("192.168.100.1", new StubX509Certificate("")
+ assertTrue(verifyWithServerCertificate("192.168.100.1", new StubX509Certificate("")
.addSubjectAlternativeName(ALT_IPA_NAME, "1.2.3.4")
.addSubjectAlternativeName(ALT_IPA_NAME, "192.168.100.1")));
}
public void testUnknownSubjectAltName() {
// Has unknown subject alternative names
- assertTrue(verifier.verify("imap.g.com", new StubX509Certificate("")
+ assertTrue(verifyWithServerCertificate("imap.g.com", new StubX509Certificate("")
.addSubjectAlternativeName(ALT_UNKNOWN, "random string 1")
.addSubjectAlternativeName(ALT_UNKNOWN, "random string 2")
.addSubjectAlternativeName(ALT_DNS_NAME, "a.b.c.d")
@@ -85,7 +98,7 @@ public final class DefaultHostnameVerifierTest extends TestCase {
.addSubjectAlternativeName(ALT_DNS_NAME, "imap.g.com")
.addSubjectAlternativeName(ALT_IPA_NAME, "2.33.44.55")
.addSubjectAlternativeName(ALT_UNKNOWN, "random string 3")));
- assertTrue(verifier.verify("2.33.44.55", new StubX509Certificate("")
+ assertTrue(verifyWithServerCertificate("2.33.44.55", new StubX509Certificate("")
.addSubjectAlternativeName(ALT_UNKNOWN, "random string 1")
.addSubjectAlternativeName(ALT_UNKNOWN, "random string 2")
.addSubjectAlternativeName(ALT_DNS_NAME, "a.b.c.d")
@@ -93,7 +106,7 @@ public final class DefaultHostnameVerifierTest extends TestCase {
.addSubjectAlternativeName(ALT_DNS_NAME, "imap.g.com")
.addSubjectAlternativeName(ALT_IPA_NAME, "2.33.44.55")
.addSubjectAlternativeName(ALT_UNKNOWN, "random string 3")));
- assertFalse(verifier.verify("g.com", new StubX509Certificate("")
+ assertFalse(verifyWithServerCertificate("g.com", new StubX509Certificate("")
.addSubjectAlternativeName(ALT_UNKNOWN, "random string 1")
.addSubjectAlternativeName(ALT_UNKNOWN, "random string 2")
.addSubjectAlternativeName(ALT_DNS_NAME, "a.b.c.d")
@@ -101,7 +114,7 @@ public final class DefaultHostnameVerifierTest extends TestCase {
.addSubjectAlternativeName(ALT_DNS_NAME, "imap.g.com")
.addSubjectAlternativeName(ALT_IPA_NAME, "2.33.44.55")
.addSubjectAlternativeName(ALT_UNKNOWN, "random string 3")));
- assertFalse(verifier.verify("2.33.44.1", new StubX509Certificate("")
+ assertFalse(verifyWithServerCertificate("2.33.44.1", new StubX509Certificate("")
.addSubjectAlternativeName(ALT_UNKNOWN, "random string 1")
.addSubjectAlternativeName(ALT_UNKNOWN, "random string 2")
.addSubjectAlternativeName(ALT_DNS_NAME, "a.b.c.d")
@@ -111,40 +124,129 @@ public final class DefaultHostnameVerifierTest extends TestCase {
.addSubjectAlternativeName(ALT_UNKNOWN, "random string 3")));
}
- public void testWildcardMatchesWildcardSuffix() {
- assertTrue(verifier.verifyHostName("b.c.d", "*.b.c.d"));
- assertTrue(verifier.verifyHostName("imap.google.com", "*.imap.google.com"));
- assertFalse(verifier.verifyHostName("imap.google.com.au", "*.imap.google.com"));
+ public void testWildcardsRejectedForIpAddress() {
+ assertFalse(verifyWithServerCertificate("1.2.3.4", new StubX509Certificate("cn=*.2.3.4")));
+ assertFalse(verifyWithServerCertificate("1.2.3.4", new StubX509Certificate("cn=*.2.3.4")
+ .addSubjectAlternativeName(ALT_IPA_NAME, "*.2.3.4")
+ .addSubjectAlternativeName(ALT_DNS_NAME, "*.2.3.4")));
+ assertFalse(verifyWithServerCertificate(
+ "2001:1234::1", new StubX509Certificate("cn=*:1234::1")));
+ assertFalse(verifyWithServerCertificate(
+ "2001:1234::1", new StubX509Certificate("cn=*:1234::1")
+ .addSubjectAlternativeName(ALT_IPA_NAME, "*:1234::1")
+ .addSubjectAlternativeName(ALT_DNS_NAME, "*:1234::1")));
+ }
+
+ public void testNullParameters() {
+ // Confirm that neither of the parameters used later in the test cause the verifier to blow
+ // up
+ String hostname = "www.example.com";
+ StubSSLSession session = new StubSSLSession();
+ session.peerCertificates =
+ new Certificate[] {new StubX509Certificate("cn=www.example.com")};
+ verifier.verify(hostname, session);
+
+ try {
+ verifier.verify(hostname, null);
+ fail();
+ } catch (NullPointerException expected) {
+ }
+
+ try {
+ verifier.verify(null, session);
+ fail();
+ } catch (NullPointerException expected) {
+ }
+ }
+
+ public void testInvalidDomainNames() {
+ assertFalse(verifyWithDomainNamePattern("", ""));
+ assertFalse(verifyWithDomainNamePattern(".test.example.com", ".test.example.com"));
+ assertFalse(verifyWithDomainNamePattern("ex*ample.com", "ex*ample.com"));
+ assertFalse(verifyWithDomainNamePattern("example.com..", "example.com."));
+ assertFalse(verifyWithDomainNamePattern("example.com.", "example.com.."));
+ }
+
+ public void testWildcardCharacterMustBeLeftMostLabelOnly() {
+ assertFalse(verifyWithDomainNamePattern("test.www.example.com", "test.*.example.com"));
+ assertFalse(verifyWithDomainNamePattern("www.example.com", "www.*.com"));
+ assertFalse(verifyWithDomainNamePattern("www.example.com", "www.example.*"));
+ assertFalse(verifyWithDomainNamePattern("www.example.com", "*www.example.com"));
+ assertFalse(verifyWithDomainNamePattern("www.example.com", "*w.example.com"));
+ assertFalse(verifyWithDomainNamePattern("www.example.com", "w*w.example.com"));
+ assertFalse(verifyWithDomainNamePattern("www.example.com", "w*.example.com"));
+ assertFalse(verifyWithDomainNamePattern("www.example.com", "www*.example.com"));
}
- public void testWildcardMatchingSubstring() {
- assertTrue(verifier.verifyHostName("b.c.d", "b*.c.d"));
- assertTrue(verifier.verifyHostName("imap.google.com", "ima*.google.com"));
- assertFalse(verifier.verifyHostName("imap.google.com.au", "ima*.google.com"));
+ public void testWildcardCannotMatchEmptyLabel() {
+ assertFalse(verifyWithDomainNamePattern("example.com", "*.example.com"));
+ assertFalse(verifyWithDomainNamePattern(".example.com", "*.example.com"));
}
- public void testWildcardMatchingEmptySubstring() {
- assertTrue(verifier.verifyHostName("imap.google.com", "imap*.google.com"));
- assertFalse(verifier.verifyHostName("imap.google.com.au", "imap*.google.com"));
+ public void testWildcardCannotMatchChildDomain() {
+ assertFalse(verifyWithDomainNamePattern("sub.www.example.com", "*.example.com"));
}
- public void testWildcardMatchesChildDomain() {
- assertFalse(verifier.verifyHostName("a.b.c.d", "*.c.d"));
+ public void testWildcardRejectedForSingleLabelPatterns() {
+ assertFalse(verifyWithDomainNamePattern("d", "*"));
+ assertFalse(verifyWithDomainNamePattern("d.", "*."));
+ assertFalse(verifyWithDomainNamePattern("d", "d*"));
+ assertFalse(verifyWithDomainNamePattern("d.", "d*."));
+ assertFalse(verifyWithDomainNamePattern("d", "*d"));
+ assertFalse(verifyWithDomainNamePattern("d.", "*d."));
+ assertFalse(verifyWithDomainNamePattern("ddd", "d*d"));
+ assertFalse(verifyWithDomainNamePattern("ddd.", "d*d."));
+ }
+
+ public void testNoPrefixMatch() {
+ assertFalse(verifyWithDomainNamePattern("imap.google.com.au", "imap.google.com"));
+ assertFalse(verifyWithDomainNamePattern("imap.google.com.au", "*.google.com"));
}
public void testVerifyHostName() {
- assertTrue(verifier.verifyHostName("a.b.c.d", "a.b.c.d"));
- assertTrue(verifier.verifyHostName("a.b.c.d", "*.b.c.d"));
- assertFalse(verifier.verifyHostName("a.b.c.d", "*.*.c.d"));
- assertTrue(verifier.verifyHostName("imap.google.com", "imap.google.com"));
- assertFalse(verifier.verifyHostName("imap2.google.com", "imap.google.com"));
- assertTrue(verifier.verifyHostName("imap.google.com", "*.google.com"));
- assertTrue(verifier.verifyHostName("imap2.google.com", "*.google.com"));
- assertFalse(verifier.verifyHostName("imap.google.com", "*.googl.com"));
- assertFalse(verifier.verifyHostName("imap2.google2.com", "*.google3.com"));
- assertFalse(verifier.verifyHostName("imap.google.com", "a*.google.com"));
- assertFalse(verifier.verifyHostName("imap.google.com", "ix*.google.com"));
- assertTrue(verifier.verifyHostName("imap.google.com", "iMap.Google.Com"));
+ assertTrue(verifyWithDomainNamePattern("a.b.c.d", "a.b.c.d"));
+ assertTrue(verifyWithDomainNamePattern("a.b.c.d", "*.b.c.d"));
+ assertFalse(verifyWithDomainNamePattern("a.b.c.d", "*.*.c.d"));
+ assertTrue(verifyWithDomainNamePattern("imap.google.com", "imap.google.com"));
+ assertFalse(verifyWithDomainNamePattern("imap2.google.com", "imap.google.com"));
+ assertTrue(verifyWithDomainNamePattern("imap.google.com", "*.google.com"));
+ assertTrue(verifyWithDomainNamePattern("imap2.google.com", "*.google.com"));
+ assertFalse(verifyWithDomainNamePattern("imap.google.com", "*.googl.com"));
+ assertFalse(verifyWithDomainNamePattern("imap2.google2.com", "*.google3.com"));
+ assertFalse(verifyWithDomainNamePattern("imap.google.com", "a*.google.com"));
+ assertFalse(verifyWithDomainNamePattern("imap.google.com", "ix*.google.com"));
+ assertTrue(verifyWithDomainNamePattern("imap.google.com", "iMap.Google.Com"));
+ assertTrue(verifyWithDomainNamePattern("weird", "weird"));
+ assertTrue(verifyWithDomainNamePattern("weird", "weird."));
+
+ // Wildcards rejected for domain names consisting of fewer than two labels (excluding root).
+ assertFalse(verifyWithDomainNamePattern("weird", "weird*"));
+ assertFalse(verifyWithDomainNamePattern("weird", "*weird"));
+ assertFalse(verifyWithDomainNamePattern("weird", "weird*."));
+ assertFalse(verifyWithDomainNamePattern("weird", "weird.*"));
+ }
+
+ public void testVerifyAbsoluteHostName() {
+ assertTrue(verifyWithDomainNamePattern("a.b.c.d.", "a.b.c.d"));
+ assertTrue(verifyWithDomainNamePattern("a.b.c.d.", "*.b.c.d"));
+ assertFalse(verifyWithDomainNamePattern("a.b.c.d.", "*.*.c.d"));
+ assertTrue(verifyWithDomainNamePattern("imap.google.com.", "imap.google.com"));
+ assertFalse(verifyWithDomainNamePattern("imap2.google.com.", "imap.google.com"));
+ assertTrue(verifyWithDomainNamePattern("imap.google.com.", "*.google.com"));
+ assertTrue(verifyWithDomainNamePattern("imap2.google.com.", "*.google.com"));
+ assertFalse(verifyWithDomainNamePattern("imap.google.com.", "*.googl.com"));
+ assertFalse(verifyWithDomainNamePattern("imap2.google2.com.", "*.google3.com"));
+ assertFalse(verifyWithDomainNamePattern("imap.google.com.", "a*.google.com"));
+ assertFalse(verifyWithDomainNamePattern("imap.google.com.", "ix*.google.com"));
+ assertTrue(verifyWithDomainNamePattern("imap.google.com.", "iMap.Google.Com"));
+ assertTrue(verifyWithDomainNamePattern("weird.", "weird"));
+ assertTrue(verifyWithDomainNamePattern("weird.", "weird."));
+
+ // Wildcards rejected for domain names consisting of fewer than two labels (excluding root).
+ assertFalse(verifyWithDomainNamePattern("weird.", "*weird"));
+ assertFalse(verifyWithDomainNamePattern("weird.", "weird*"));
+ assertFalse(verifyWithDomainNamePattern("weird.", "weird*."));
+ assertFalse(verifyWithDomainNamePattern("weird.", "weird.*"));
}
public void testSubjectOnlyCert() throws Exception {
@@ -168,8 +270,8 @@ public final class DefaultHostnameVerifierTest extends TestCase {
+ "rs2oQLwOLnuifH52ey9+tJguabo+brlYYigAuWWFEzJfBzikDkIwnE/L7wlrypIk\n"
+ "taXDWI4=\n"
+ "-----END CERTIFICATE-----");
- assertTrue(verifier.verify("www.example.com", cert));
- assertFalse(verifier.verify("www2.example.com", cert));
+ assertTrue(verifyWithServerCertificate("www.example.com", cert));
+ assertFalse(verifyWithServerCertificate("www2.example.com", cert));
}
public void testSubjectAltOnlyCert() throws Exception {
@@ -192,8 +294,8 @@ public final class DefaultHostnameVerifierTest extends TestCase {
+ "JPRynf9244Pn0Sr/wsnmdsTRFIFYynrc51hQ7DkwbUxpcaewkZzilru/SwZ3+pPT\n"
+ "9JSqm5hJ1pg5WDlPkW7c/1VA0/141N52Q8MIU+2ZpuOj\n"
+ "-----END CERTIFICATE-----");
- assertTrue(verifier.verify("www.example.com", cert));
- assertFalse(verifier.verify("www2.example.com", cert));
+ assertTrue(verifyWithServerCertificate("www.example.com", cert));
+ assertFalse(verifyWithServerCertificate("www2.example.com", cert));
}
public void testSubjectWithAltNamesCert() throws Exception {
@@ -219,10 +321,10 @@ public final class DefaultHostnameVerifierTest extends TestCase {
+ "hrTVypLSoRXuTB2aWilu4p6aNh84xTdyqo2avtNr2MiQMZIcdamBq8LdBIAShFXI\n"
+ "h5G2eVGXH/Y=\n"
+ "-----END CERTIFICATE-----");
- assertFalse(verifier.verify("www.example.com", cert));
- assertTrue(verifier.verify("www2.example.com", cert));
- assertTrue(verifier.verify("www3.example.com", cert));
- assertFalse(verifier.verify("www4.example.com", cert));
+ assertFalse(verifyWithServerCertificate("www.example.com", cert));
+ assertTrue(verifyWithServerCertificate("www2.example.com", cert));
+ assertTrue(verifyWithServerCertificate("www3.example.com", cert));
+ assertFalse(verifyWithServerCertificate("www4.example.com", cert));
}
public void testSubjectWithWildAltNamesCert() throws Exception {
@@ -247,11 +349,11 @@ public final class DefaultHostnameVerifierTest extends TestCase {
+ "Y3R0HZvKzNIU3pwAm69HCJoG+/9MZEIDJb0WJc5UygxDT45XE9zQMQe4dBOTaNXT\n"
+ "+ntgaB62kE10HzrzpqXAgoAWxWK4RzFcUpBWw9qYq9xOCewJ\n"
+ "-----END CERTIFICATE-----");
- assertFalse(verifier.verify("www.example.com", cert));
- assertFalse(verifier.verify("www2.example.com", cert));
- assertTrue(verifier.verify("www.example2.com", cert));
- assertTrue(verifier.verify("abc.example2.com", cert));
- assertFalse(verifier.verify("www.example3.com", cert));
+ assertFalse(verifyWithServerCertificate("www.example.com", cert));
+ assertFalse(verifyWithServerCertificate("www2.example.com", cert));
+ assertTrue(verifyWithServerCertificate("www.example2.com", cert));
+ assertTrue(verifyWithServerCertificate("abc.example2.com", cert));
+ assertFalse(verifyWithServerCertificate("www.example3.com", cert));
}
public void testWildAltNameOnlyCert() throws Exception {
@@ -274,9 +376,9 @@ public final class DefaultHostnameVerifierTest extends TestCase {
+ "va++ow5r1VxQXFJc0ZPzsDo+6TlktoDHaRQJGMqQomqHWT4i7F5UZgf6BHGfEUPU\n"
+ "qep+GsF3QRHSBtpObWkVDZNFvky3a1iZ2q25+hFIqQ==\n"
+ "-----END CERTIFICATE-----");
- assertTrue(verifier.verify("www.example.com", cert));
- assertTrue(verifier.verify("www2.example.com", cert));
- assertFalse(verifier.verify("www.example2.com", cert));
+ assertTrue(verifyWithServerCertificate("www.example.com", cert));
+ assertTrue(verifyWithServerCertificate("www2.example.com", cert));
+ assertFalse(verifyWithServerCertificate("www.example2.com", cert));
}
public void testAltIpOnlyCert() throws Exception {
@@ -299,8 +401,48 @@ public final class DefaultHostnameVerifierTest extends TestCase {
+ "WPjHQcWfpkFzAF5wyOq0kveVfx0g5xPhOVDd+U+q7WastbXICpCoHp9FxISmZVik\n"
+ "sAyifp8agkYdzaSh55fFmKXlFnRsQw==\n"
+ "-----END CERTIFICATE-----");
- assertTrue(verifier.verify("192.168.10.1", cert));
- assertFalse(verifier.verify("192.168.10.2", cert));
+ assertTrue(verifyWithServerCertificate("192.168.10.1", cert));
+ assertFalse(verifyWithServerCertificate("192.168.10.2", cert));
+ }
+
+ /**
+ * Verifies the provided hostname against the provided domain name pattern from server
+ * certificate.
+ */
+ private boolean verifyWithDomainNamePattern(String hostname, String pattern) {
+ StubSSLSession session = new StubSSLSession();
+
+ // Verify using a certificate where the pattern is in the CN
+ session.peerCertificates = new Certificate[] {
+ new StubX509Certificate("cn=\"" + pattern + "\"")
+ };
+ boolean resultWhenPatternInCn = verifier.verify(hostname, session);
+
+ // Verify using a certificate where the pattern is in a DNS SubjectAltName
+ session.peerCertificates = new Certificate[] {
+ new StubX509Certificate("ou=test")
+ .addSubjectAlternativeName(ALT_DNS_NAME, pattern)
+ };
+ boolean resultWhenPatternInSubjectAltName = verifier.verify(hostname, session);
+
+ // Assert that in both cases the verifier gives the same result
+ if (resultWhenPatternInCn != resultWhenPatternInSubjectAltName) {
+ fail("Different results between pattern in CN and SubjectAltName."
+ + " hostname : " + hostname + ", pattern: " + pattern
+ + ", when pattern in CN: " + resultWhenPatternInCn
+ + ", when pattern in SubjectAltName: " + resultWhenPatternInSubjectAltName);
+ }
+ return resultWhenPatternInCn;
+ }
+
+ /**
+ * Verifies the provided hostname against the provided server certificate.
+ */
+ private boolean verifyWithServerCertificate(String hostname, X509Certificate certificate) {
+ StubSSLSession session = new StubSSLSession();
+ session.peerCertificates =
+ (certificate != null) ? new Certificate[] {certificate} : new Certificate[0];
+ return verifier.verify(hostname, session);
}
X509Certificate parseCertificate(String encoded) throws Exception {
@@ -308,6 +450,117 @@ public final class DefaultHostnameVerifierTest extends TestCase {
return (X509Certificate) CertificateFactory.getInstance("X509").generateCertificate(in);
}
+ private static class StubSSLSession implements SSLSession {
+
+ public Certificate[] peerCertificates = new Certificate[0];
+
+ @Override
+ public int getApplicationBufferSize() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public String getCipherSuite() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public long getCreationTime() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public byte[] getId() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public long getLastAccessedTime() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Certificate[] getLocalCertificates() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Principal getLocalPrincipal() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public int getPacketBufferSize() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public javax.security.cert.X509Certificate[] getPeerCertificateChain()
+ throws SSLPeerUnverifiedException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Certificate[] getPeerCertificates() throws SSLPeerUnverifiedException {
+ return peerCertificates;
+ }
+
+ @Override
+ public String getPeerHost() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public int getPeerPort() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Principal getPeerPrincipal() throws SSLPeerUnverifiedException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public String getProtocol() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public SSLSessionContext getSessionContext() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Object getValue(String name) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public String[] getValueNames() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void invalidate() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public boolean isValid() {
+ return true;
+ }
+
+ @Override
+ public void putValue(String name, Object value) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void removeValue(String name) {
+ throw new UnsupportedOperationException();
+ }
+ }
+
private static class StubX509Certificate extends X509Certificate {
private final X500Principal subjectX500Principal;
private Collection<List<?>> subjectAlternativeNames;
diff --git a/luni/src/test/java/libcore/javax/net/ssl/HttpsURLConnectionTest.java b/luni/src/test/java/libcore/javax/net/ssl/HttpsURLConnectionTest.java
new file mode 100644
index 0000000..cbaea20
--- /dev/null
+++ b/luni/src/test/java/libcore/javax/net/ssl/HttpsURLConnectionTest.java
@@ -0,0 +1,115 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package libcore.javax.net.ssl;
+
+import junit.framework.TestCase;
+
+import java.io.IOException;
+import java.net.URL;
+
+import javax.net.ssl.HostnameVerifier;
+import javax.net.ssl.HttpsURLConnection;
+import javax.net.ssl.SSLSession;
+import javax.net.ssl.SSLSocketFactory;
+
+public class HttpsURLConnectionTest extends TestCase {
+
+ /**
+ * HTTPS URL which cannot be resolved and is thus safe to use in tests where network traffic
+ * should be avoided.
+ */
+ private static final String UNRESOLVABLE_HTTPS_URL = "https:///";
+
+ public void testDefaultHostnameVerifierNotNull() {
+ assertNotNull(HttpsURLConnection.getDefaultHostnameVerifier());
+ }
+
+ public void testDefaultHostnameVerifierUsedForNewConnectionsByDefault() throws IOException {
+ HostnameVerifier originalHostnameVerifier = HttpsURLConnection.getDefaultHostnameVerifier();
+ HttpsURLConnection connection =
+ (HttpsURLConnection) new URL(UNRESOLVABLE_HTTPS_URL).openConnection();
+ try {
+ assertSame(originalHostnameVerifier, connection.getHostnameVerifier());
+ } finally {
+ connection.disconnect();
+ }
+
+ HostnameVerifier anotherVerifier = new FakeHostnameVerifier();
+ try {
+ HttpsURLConnection.setDefaultHostnameVerifier(anotherVerifier);
+ connection = (HttpsURLConnection) new URL(UNRESOLVABLE_HTTPS_URL).openConnection();
+ try {
+ assertSame(anotherVerifier, connection.getHostnameVerifier());
+ } finally {
+ connection.disconnect();
+ }
+
+ HttpsURLConnection.setDefaultHostnameVerifier(originalHostnameVerifier);
+ connection = (HttpsURLConnection) new URL(UNRESOLVABLE_HTTPS_URL).openConnection();
+ try {
+ assertSame(originalHostnameVerifier, connection.getHostnameVerifier());
+ } finally {
+ connection.disconnect();
+ }
+ } finally {
+ HttpsURLConnection.setDefaultHostnameVerifier(originalHostnameVerifier);
+ }
+ }
+
+ public void testDefaultSSLSocketFactoryNotNull() {
+ assertNotNull(HttpsURLConnection.getDefaultSSLSocketFactory());
+ }
+
+ public void testDefaultSSLSocketFactoryUsedForNewConnectionsByDefault() throws IOException {
+ SSLSocketFactory originalFactory = HttpsURLConnection.getDefaultSSLSocketFactory();
+ HttpsURLConnection connection =
+ (HttpsURLConnection) new URL(UNRESOLVABLE_HTTPS_URL).openConnection();
+ try {
+ assertSame(originalFactory, connection.getSSLSocketFactory());
+ } finally {
+ connection.disconnect();
+ }
+
+ SSLSocketFactory anotherFactory = new SSLSocketFactoryTest.FakeSSLSocketFactory();
+ try {
+ HttpsURLConnection.setDefaultSSLSocketFactory(anotherFactory);
+ connection = (HttpsURLConnection) new URL(UNRESOLVABLE_HTTPS_URL).openConnection();
+ try {
+ assertSame(anotherFactory, connection.getSSLSocketFactory());
+ } finally {
+ connection.disconnect();
+ }
+
+ HttpsURLConnection.setDefaultSSLSocketFactory(originalFactory);
+ connection = (HttpsURLConnection) new URL(UNRESOLVABLE_HTTPS_URL).openConnection();
+ try {
+ assertSame(originalFactory, connection.getSSLSocketFactory());
+ } finally {
+ connection.disconnect();
+ }
+ } finally {
+ HttpsURLConnection.setDefaultSSLSocketFactory(originalFactory);
+ }
+ }
+
+ private static class FakeHostnameVerifier implements HostnameVerifier {
+ @Override
+ public boolean verify(String hostname, SSLSession session) {
+ return true;
+ }
+ }
+}
diff --git a/luni/src/test/java/libcore/javax/net/ssl/SSLContextTest.java b/luni/src/test/java/libcore/javax/net/ssl/SSLContextTest.java
index dccadbd..533849c 100644
--- a/luni/src/test/java/libcore/javax/net/ssl/SSLContextTest.java
+++ b/luni/src/test/java/libcore/javax/net/ssl/SSLContextTest.java
@@ -26,7 +26,6 @@ import java.security.Security;
import java.security.UnrecoverableKeyException;
import java.util.ArrayList;
import java.util.Arrays;
-import java.util.Collections;
import java.util.List;
import java.util.concurrent.Callable;
import libcore.io.IoUtils;
@@ -82,14 +81,14 @@ public class SSLContextTest extends TestCase {
}
public void test_SSLContext_defaultConfiguration() throws Exception {
- SSLDefaultConfigurationAsserts.assertSSLContext(SSLContext.getDefault());
+ SSLConfigurationAsserts.assertSSLContextDefaultConfiguration(SSLContext.getDefault());
for (String protocol : StandardNames.SSL_CONTEXT_PROTOCOLS) {
SSLContext sslContext = SSLContext.getInstance(protocol);
if (!protocol.equals(StandardNames.SSL_CONTEXT_PROTOCOLS_DEFAULT)) {
sslContext.init(null, null, null);
}
- SSLDefaultConfigurationAsserts.assertSSLContext(sslContext);
+ SSLConfigurationAsserts.assertSSLContextDefaultConfiguration(sslContext);
}
}
@@ -149,6 +148,27 @@ public class SSLContextTest extends TestCase {
sslContext);
}
+ public void test_SSLContext_init_correctProtocolVersionsEnabled() throws Exception {
+ for (String tlsVersion : StandardNames.SSL_CONTEXT_PROTOCOLS) {
+ // Don't test the "Default" instance.
+ if (StandardNames.SSL_CONTEXT_PROTOCOLS_DEFAULT.equals(tlsVersion)) {
+ continue;
+ }
+
+ SSLContext context = SSLContext.getInstance(tlsVersion);
+ context.init(null, null, null);
+
+ StandardNames.assertSSLContextEnabledProtocols(tlsVersion, ((SSLSocket) (context.getSocketFactory()
+ .createSocket())).getEnabledProtocols());
+ StandardNames.assertSSLContextEnabledProtocols(tlsVersion, ((SSLServerSocket) (context
+ .getServerSocketFactory().createServerSocket())).getEnabledProtocols());
+ StandardNames.assertSSLContextEnabledProtocols(tlsVersion, context.getDefaultSSLParameters()
+ .getProtocols());
+ StandardNames.assertSSLContextEnabledProtocols(tlsVersion, context.createSSLEngine()
+ .getEnabledProtocols());
+ }
+ }
+
private static void assertEnabledCipherSuites(
List<String> expectedCipherSuites, SSLContext sslContext) throws Exception {
assertContentsInOrder(
diff --git a/luni/src/test/java/libcore/javax/net/ssl/SSLEngineTest.java b/luni/src/test/java/libcore/javax/net/ssl/SSLEngineTest.java
index df4585f..5e3a3d5 100644
--- a/luni/src/test/java/libcore/javax/net/ssl/SSLEngineTest.java
+++ b/luni/src/test/java/libcore/javax/net/ssl/SSLEngineTest.java
@@ -65,7 +65,7 @@ public class SSLEngineTest extends TestCase {
}
public void test_SSLEngine_defaultConfiguration() throws Exception {
- SSLDefaultConfigurationAsserts.assertSSLEngine(
+ SSLConfigurationAsserts.assertSSLEngineDefaultConfiguration(
TestSSLContext.create().clientContext.createSSLEngine());
}
@@ -203,24 +203,31 @@ public class SSLEngineTest extends TestCase {
: new String[] { cipherSuite });
// Check that handshake succeeds.
- TestSSLEnginePair pair = TestSSLEnginePair.create(c, new TestSSLEnginePair.Hooks() {
- @Override
- void beforeBeginHandshake(SSLEngine client, SSLEngine server) {
- client.setEnabledCipherSuites(cipherSuiteArray);
- server.setEnabledCipherSuites(cipherSuiteArray);
+ TestSSLEnginePair pair = null;
+ try {
+ pair = TestSSLEnginePair.create(c, new TestSSLEnginePair.Hooks() {
+ @Override
+ void beforeBeginHandshake(SSLEngine client, SSLEngine server) {
+ client.setEnabledCipherSuites(cipherSuiteArray);
+ server.setEnabledCipherSuites(cipherSuiteArray);
+ }
+ });
+ assertConnected(pair);
+
+ boolean needsRecordSplit =
+ ("TLS".equalsIgnoreCase(c.clientContext.getProtocol())
+ || "SSLv3".equalsIgnoreCase(c.clientContext.getProtocol()))
+ && cipherSuite.contains("_CBC_");
+
+ assertSendsCorrectly("This is the client. Hello!".getBytes(),
+ pair.client, pair.server, needsRecordSplit);
+ assertSendsCorrectly("This is the server. Hi!".getBytes(),
+ pair.server, pair.client, needsRecordSplit);
+ } finally {
+ if (pair != null) {
+ pair.close();
}
- });
- assertConnected(pair);
-
- boolean needsRecordSplit =
- ("TLS".equalsIgnoreCase(c.clientContext.getProtocol())
- || "SSLv3".equalsIgnoreCase(c.clientContext.getProtocol()))
- && cipherSuite.contains("_CBC_");
-
- assertSendsCorrectly("This is the client. Hello!".getBytes(),
- pair.client, pair.server, needsRecordSplit);
- assertSendsCorrectly("This is the server. Hi!".getBytes(),
- pair.server, pair.client, needsRecordSplit);
+ }
// Check that handshake fails when the server does not possess the private key
// corresponding to the server's certificate. This is achieved by using SSLContext
@@ -234,17 +241,23 @@ public class SSLEngineTest extends TestCase {
serverAuthenticatedUsingPublicKey = false;
}
if (serverAuthenticatedUsingPublicKey) {
+ TestSSLEnginePair p = null;
try {
- TestSSLEnginePair p = TestSSLEnginePair.create(
+ p = TestSSLEnginePair.create(
cWithWrongPrivateKeys, new TestSSLEnginePair.Hooks() {
- @Override
+ @Override
void beforeBeginHandshake(SSLEngine client, SSLEngine server) {
- client.setEnabledCipherSuites(cipherSuiteArray);
- server.setEnabledCipherSuites(cipherSuiteArray);
- }
- });
+ client.setEnabledCipherSuites(cipherSuiteArray);
+ server.setEnabledCipherSuites(cipherSuiteArray);
+ }
+ });
assertNotConnected(p);
- } catch (IOException expected) {}
+ } catch (IOException expected) {
+ } finally {
+ if (p != null) {
+ p.close();
+ }
+ }
}
} catch (Exception e) {
String message = ("Problem trying to connect cipher suite " + cipherSuite);
@@ -432,21 +445,28 @@ public class SSLEngineTest extends TestCase {
fail();
} catch (IllegalStateException expected) {
}
+ c.close();
- assertConnected(TestSSLEnginePair.create(null));
+ TestSSLEnginePair p = TestSSLEnginePair.create(null);
+ assertConnected(p);
+ p.close();
- c.close();
}
public void test_SSLEngine_beginHandshake_noKeyStore() throws Exception {
TestSSLContext c = TestSSLContext.create(null, null, null, null, null, null, null, null,
SSLContext.getDefault(), SSLContext.getDefault());
+ SSLEngine[] p = null;
try {
// TODO Fix KnownFailure AlertException "NO SERVER CERTIFICATE FOUND"
// ServerHandshakeImpl.selectSuite should not select a suite without a required cert
- TestSSLEnginePair.connect(c, null);
+ p = TestSSLEnginePair.connect(c, null);
fail();
} catch (SSLHandshakeException expected) {
+ } finally {
+ if (p != null) {
+ TestSSLEnginePair.close(p);
+ }
}
c.close();
}
@@ -456,6 +476,7 @@ public class SSLEngineTest extends TestCase {
SSLEngine[] engines = TestSSLEnginePair.connect(c, null);
assertConnected(engines[0], engines[1]);
c.close();
+ TestSSLEnginePair.close(engines);
}
public void test_SSLEngine_getUseClientMode() throws Exception {
@@ -467,33 +488,47 @@ public class SSLEngineTest extends TestCase {
public void test_SSLEngine_setUseClientMode() throws Exception {
boolean[] finished;
+ TestSSLEnginePair p = null;
// client is client, server is server
finished = new boolean[2];
- assertConnected(test_SSLEngine_setUseClientMode(true, false, finished));
+ p = test_SSLEngine_setUseClientMode(true, false, finished);
+ assertConnected(p);
assertTrue(finished[0]);
assertTrue(finished[1]);
+ p.close();
// client is server, server is client
finished = new boolean[2];
- assertConnected(test_SSLEngine_setUseClientMode(false, true, finished));
+ p = test_SSLEngine_setUseClientMode(false, true, finished);
+ assertConnected(p);
assertTrue(finished[0]);
assertTrue(finished[1]);
+ p.close();
// both are client
/*
* Our implementation throws an SSLHandshakeException, but RI just
* stalls forever
*/
+ p = null;
try {
- assertNotConnected(test_SSLEngine_setUseClientMode(true, true, null));
+ p = test_SSLEngine_setUseClientMode(true, true, null);
+ assertNotConnected(p);
assertTrue(StandardNames.IS_RI);
} catch (SSLHandshakeException maybeExpected) {
assertFalse(StandardNames.IS_RI);
+ } finally {
+ if (p != null) {
+ p.close();
+ }
+
}
+ p = test_SSLEngine_setUseClientMode(false, false, null);
// both are server
- assertNotConnected(test_SSLEngine_setUseClientMode(false, false, null));
+ assertNotConnected(p);
+ p.close();
}
public void test_SSLEngine_setUseClientMode_afterHandshake() throws Exception {
@@ -510,6 +545,7 @@ public class SSLEngineTest extends TestCase {
fail();
} catch (IllegalArgumentException expected) {
}
+ pair.close();
}
private TestSSLEnginePair test_SSLEngine_setUseClientMode(final boolean clientClientMode,
@@ -572,6 +608,7 @@ public class SSLEngineTest extends TestCase {
p.client.getSession().getLocalCertificates());
clientAuthContext.close();
c.close();
+ p.close();
}
/**
@@ -591,6 +628,7 @@ public class SSLEngineTest extends TestCase {
});
assertConnected(p);
clientAuthContext.close();
+ p.close();
}
/**
@@ -604,8 +642,9 @@ public class SSLEngineTest extends TestCase {
TestSSLContext clientAuthContext
= TestSSLContext.create(TestKeyStore.getClient(),
TestKeyStore.getServer());
+ TestSSLEnginePair p = null;
try {
- TestSSLEnginePair.create(clientAuthContext,
+ p = TestSSLEnginePair.create(clientAuthContext,
new TestSSLEnginePair.Hooks() {
@Override
void beforeBeginHandshake(SSLEngine client, SSLEngine server) {
@@ -616,6 +655,9 @@ public class SSLEngineTest extends TestCase {
} catch (SSLHandshakeException expected) {
} finally {
clientAuthContext.close();
+ if (p != null) {
+ p.close();
+ }
}
}
@@ -624,11 +666,13 @@ public class SSLEngineTest extends TestCase {
SSLEngine e = c.clientContext.createSSLEngine();
assertTrue(e.getEnableSessionCreation());
c.close();
+ TestSSLEnginePair.close(new SSLEngine[] { e });
}
public void test_SSLEngine_setEnableSessionCreation_server() throws Exception {
+ TestSSLEnginePair p = null;
try {
- TestSSLEnginePair p = TestSSLEnginePair.create(new TestSSLEnginePair.Hooks() {
+ p = TestSSLEnginePair.create(new TestSSLEnginePair.Hooks() {
@Override
void beforeBeginHandshake(SSLEngine client, SSLEngine server) {
server.setEnableSessionCreation(false);
@@ -639,12 +683,17 @@ public class SSLEngineTest extends TestCase {
assertNotConnected(p);
} catch (SSLException maybeExpected) {
assertFalse(StandardNames.IS_RI);
+ } finally {
+ if (p != null) {
+ p.close();
+ }
}
}
public void test_SSLEngine_setEnableSessionCreation_client() throws Exception {
+ TestSSLEnginePair p = null;
try {
- TestSSLEnginePair.create(new TestSSLEnginePair.Hooks() {
+ p = TestSSLEnginePair.create(new TestSSLEnginePair.Hooks() {
@Override
void beforeBeginHandshake(SSLEngine client, SSLEngine server) {
client.setEnableSessionCreation(false);
@@ -652,6 +701,10 @@ public class SSLEngineTest extends TestCase {
});
fail();
} catch (SSLException expected) {
+ } finally {
+ if (p != null) {
+ p.close();
+ }
}
}
@@ -735,5 +788,6 @@ public class SSLEngineTest extends TestCase {
assertNotNull(test.server);
assertNotNull(test.client);
assertConnected(test);
+ test.close();
}
}
diff --git a/luni/src/test/java/libcore/javax/net/ssl/SSLServerSocketFactoryTest.java b/luni/src/test/java/libcore/javax/net/ssl/SSLServerSocketFactoryTest.java
index ea9c3f0..cda1fb8 100644
--- a/luni/src/test/java/libcore/javax/net/ssl/SSLServerSocketFactoryTest.java
+++ b/luni/src/test/java/libcore/javax/net/ssl/SSLServerSocketFactoryTest.java
@@ -22,7 +22,7 @@ import junit.framework.TestCase;
public class SSLServerSocketFactoryTest extends TestCase {
public void testDefaultConfiguration() throws Exception {
- SSLDefaultConfigurationAsserts.assertSSLServerSocketFactory(
+ SSLConfigurationAsserts.assertSSLServerSocketFactoryDefaultConfiguration(
(SSLServerSocketFactory) SSLServerSocketFactory.getDefault());
}
}
diff --git a/luni/src/test/java/libcore/javax/net/ssl/SSLServerSocketTest.java b/luni/src/test/java/libcore/javax/net/ssl/SSLServerSocketTest.java
index 59c44c1..d2c0f48 100644
--- a/luni/src/test/java/libcore/javax/net/ssl/SSLServerSocketTest.java
+++ b/luni/src/test/java/libcore/javax/net/ssl/SSLServerSocketTest.java
@@ -24,7 +24,7 @@ import java.util.Arrays;
public class SSLServerSocketTest extends TestCase {
public void testDefaultConfiguration() throws Exception {
- SSLDefaultConfigurationAsserts.assertSSLServerSocket(
+ SSLConfigurationAsserts.assertSSLServerSocketDefaultConfiguration(
(SSLServerSocket) SSLServerSocketFactory.getDefault().createServerSocket());
}
diff --git a/luni/src/test/java/libcore/javax/net/ssl/SSLSessionTest.java b/luni/src/test/java/libcore/javax/net/ssl/SSLSessionTest.java
index a434d94..bc2b626 100644
--- a/luni/src/test/java/libcore/javax/net/ssl/SSLSessionTest.java
+++ b/luni/src/test/java/libcore/javax/net/ssl/SSLSessionTest.java
@@ -99,7 +99,7 @@ public class SSLSessionTest extends TestCase {
assertTrue("s.server.getLastAccessedTime()=" + s.server.getLastAccessedTime() + " " +
"s.client.getLastAccessedTime()=" + s.client.getLastAccessedTime(),
Math.abs(s.server.getLastAccessedTime()
- - s.client.getLastAccessedTime()) < 1 * 1000);
+ - s.client.getLastAccessedTime()) <= 1 * 1000);
assertTrue(s.server.getLastAccessedTime() >=
s.server.getCreationTime());
assertTrue(s.client.getLastAccessedTime() >=
diff --git a/luni/src/test/java/libcore/javax/net/ssl/SSLSocketFactoryTest.java b/luni/src/test/java/libcore/javax/net/ssl/SSLSocketFactoryTest.java
index acf69c0..83b690b 100644
--- a/luni/src/test/java/libcore/javax/net/ssl/SSLSocketFactoryTest.java
+++ b/luni/src/test/java/libcore/javax/net/ssl/SSLSocketFactoryTest.java
@@ -210,7 +210,7 @@ public class SSLSocketFactoryTest extends TestCase {
}
public void test_SSLSocketFactory_defaultConfiguration() throws Exception {
- SSLDefaultConfigurationAsserts.assertSSLSocketFactory(
+ SSLConfigurationAsserts.assertSSLSocketFactoryDefaultConfiguration(
(SSLSocketFactory) SSLSocketFactory.getDefault());
}
diff --git a/luni/src/test/java/libcore/javax/net/ssl/SSLSocketTest.java b/luni/src/test/java/libcore/javax/net/ssl/SSLSocketTest.java
index 4af7f5a..bf2d0f8 100644
--- a/luni/src/test/java/libcore/javax/net/ssl/SSLSocketTest.java
+++ b/luni/src/test/java/libcore/javax/net/ssl/SSLSocketTest.java
@@ -16,6 +16,8 @@
package libcore.javax.net.ssl;
+import java.io.ByteArrayInputStream;
+import java.io.DataInputStream;
import java.io.EOFException;
import java.io.IOException;
import java.io.InputStream;
@@ -26,15 +28,18 @@ import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.Socket;
-import java.net.SocketAddress;
import java.net.SocketException;
import java.net.SocketTimeoutException;
+import java.security.KeyManagementException;
+import java.security.NoSuchAlgorithmException;
import java.security.Principal;
import java.security.PrivateKey;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
+import java.util.ArrayList;
import java.util.Arrays;
+import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
@@ -66,11 +71,23 @@ import libcore.io.IoUtils;
import libcore.io.Streams;
import libcore.java.security.StandardNames;
import libcore.java.security.TestKeyStore;
+import libcore.tlswire.handshake.CipherSuite;
+import libcore.tlswire.handshake.ClientHello;
+import libcore.tlswire.handshake.CompressionMethod;
+import libcore.tlswire.handshake.HandshakeMessage;
+import libcore.tlswire.handshake.HelloExtension;
+import libcore.tlswire.handshake.ServerNameHelloExtension;
+import libcore.tlswire.record.TlsProtocols;
+import libcore.tlswire.record.TlsRecord;
+import libcore.tlswire.util.TlsProtocolVersion;
+import tests.util.ForEachRunner;
+import tests.util.DelegatingSSLSocketFactory;
+import tests.util.Pair;
public class SSLSocketTest extends TestCase {
public void test_SSLSocket_defaultConfiguration() throws Exception {
- SSLDefaultConfigurationAsserts.assertSSLSocket(
+ SSLConfigurationAsserts.assertSSLSocketDefaultConfiguration(
(SSLSocket) SSLSocketFactory.getDefault().createSocket());
}
@@ -403,6 +420,37 @@ public class SSLSocketTest extends TestCase {
c.close();
}
+ public void test_SSLSocket_NoEnabledCipherSuites_Failure() throws Exception {
+ TestSSLContext c = TestSSLContext.create(null, null, null, null, null, null, null, null,
+ SSLContext.getDefault(), SSLContext.getDefault());
+ SSLSocket client = (SSLSocket) c.clientContext.getSocketFactory().createSocket(c.host,
+ c.port);
+ client.setEnabledCipherSuites(new String[0]);
+ final SSLSocket server = (SSLSocket) c.serverSocket.accept();
+ ExecutorService executor = Executors.newSingleThreadExecutor();
+ Future<Void> future = executor.submit(new Callable<Void>() {
+ @Override
+ public Void call() throws Exception {
+ try {
+ server.startHandshake();
+ fail();
+ } catch (SSLHandshakeException expected) {
+ }
+ return null;
+ }
+ });
+ executor.shutdown();
+ try {
+ client.startHandshake();
+ fail();
+ } catch (SSLHandshakeException expected) {
+ }
+ future.get();
+ server.close();
+ client.close();
+ c.close();
+ }
+
public void test_SSLSocket_startHandshake_noKeyStore() throws Exception {
TestSSLContext c = TestSSLContext.create(null, null, null, null, null, null, null, null,
SSLContext.getDefault(), SSLContext.getDefault());
@@ -1458,11 +1506,147 @@ public class SSLSocketTest extends TestCase {
test.close();
}
- public void test_SSLSocket_ClientHello_size() throws Exception {
+ public void test_SSLSocket_ClientHello_record_size() throws Exception {
// This test checks the size of ClientHello of the default SSLSocket. TLS/SSL handshakes
// with older/unpatched F5/BIG-IP appliances are known to stall and time out when
// the fragment containing ClientHello is between 256 and 511 (inclusive) bytes long.
- //
+ SSLContext sslContext = SSLContext.getInstance("TLS");
+ sslContext.init(null, null, null);
+ SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory();
+ sslSocketFactory = new DelegatingSSLSocketFactory(sslSocketFactory) {
+ @Override
+ protected void configureSocket(SSLSocket socket) {
+ // Enable SNI extension on the socket (this is typically enabled by default)
+ // to increase the size of ClientHello.
+ try {
+ Method setHostname =
+ socket.getClass().getMethod("setHostname", String.class);
+ setHostname.invoke(socket, "sslsockettest.androidcts.google.com");
+ } catch (NoSuchMethodException ignored) {
+ } catch (Exception e) {
+ throw new RuntimeException("Failed to enable SNI", e);
+ }
+
+ // Enable Session Tickets extension on the socket (this is typically enabled
+ // by default) to increase the size of ClientHello.
+ try {
+ Method setUseSessionTickets =
+ socket.getClass().getMethod(
+ "setUseSessionTickets", boolean.class);
+ setUseSessionTickets.invoke(socket, true);
+ } catch (NoSuchMethodException ignored) {
+ } catch (Exception e) {
+ throw new RuntimeException("Failed to enable Session Tickets", e);
+ }
+ }
+ };
+
+ TlsRecord firstReceivedTlsRecord = captureTlsHandshakeFirstTlsRecord(sslSocketFactory);
+ assertEquals("TLS record type", TlsProtocols.HANDSHAKE, firstReceivedTlsRecord.type);
+ HandshakeMessage handshakeMessage = HandshakeMessage.read(
+ new DataInputStream(new ByteArrayInputStream(firstReceivedTlsRecord.fragment)));
+ assertEquals("HandshakeMessage type",
+ HandshakeMessage.TYPE_CLIENT_HELLO, handshakeMessage.type);
+ int fragmentLength = firstReceivedTlsRecord.fragment.length;
+ if ((fragmentLength >= 256) && (fragmentLength <= 511)) {
+ fail("Fragment containing ClientHello is of dangerous length: "
+ + fragmentLength + " bytes");
+ }
+ }
+
+ public void test_SSLSocket_ClientHello_cipherSuites() throws Exception {
+ ForEachRunner.runNamed(new ForEachRunner.Callback<SSLSocketFactory>() {
+ @Override
+ public void run(SSLSocketFactory sslSocketFactory) throws Exception {
+ ClientHello clientHello = captureTlsHandshakeClientHello(sslSocketFactory);
+ String[] cipherSuites = new String[clientHello.cipherSuites.size()];
+ for (int i = 0; i < clientHello.cipherSuites.size(); i++) {
+ CipherSuite cipherSuite = clientHello.cipherSuites.get(i);
+ cipherSuites[i] = cipherSuite.getAndroidName();
+ }
+ StandardNames.assertDefaultCipherSuites(cipherSuites);
+ }
+ }, getSSLSocketFactoriesToTest());
+ }
+
+ public void test_SSLSocket_ClientHello_clientProtocolVersion() throws Exception {
+ ForEachRunner.runNamed(new ForEachRunner.Callback<SSLSocketFactory>() {
+ @Override
+ public void run(SSLSocketFactory sslSocketFactory) throws Exception {
+ ClientHello clientHello = captureTlsHandshakeClientHello(sslSocketFactory);
+ assertEquals(TlsProtocolVersion.TLSv1_2, clientHello.clientVersion);
+ }
+ }, getSSLSocketFactoriesToTest());
+ }
+
+ public void test_SSLSocket_ClientHello_compressionMethods() throws Exception {
+ ForEachRunner.runNamed(new ForEachRunner.Callback<SSLSocketFactory>() {
+ @Override
+ public void run(SSLSocketFactory sslSocketFactory) throws Exception {
+ ClientHello clientHello = captureTlsHandshakeClientHello(sslSocketFactory);
+ assertEquals(Arrays.asList(CompressionMethod.NULL), clientHello.compressionMethods);
+ }
+ }, getSSLSocketFactoriesToTest());
+ }
+
+ public void test_SSLSocket_ClientHello_SNI() throws Exception {
+ ForEachRunner.runNamed(new ForEachRunner.Callback<SSLSocketFactory>() {
+ @Override
+ public void run(SSLSocketFactory sslSocketFactory) throws Exception {
+ ClientHello clientHello = captureTlsHandshakeClientHello(sslSocketFactory);
+ ServerNameHelloExtension sniExtension = (ServerNameHelloExtension)
+ clientHello.findExtensionByType(HelloExtension.TYPE_SERVER_NAME);
+ assertNotNull(sniExtension);
+ assertEquals(Arrays.asList("localhost.localdomain"), sniExtension.hostnames);
+ }
+ }, getSSLSocketFactoriesToTest());
+ }
+
+ private List<Pair<String, SSLSocketFactory>> getSSLSocketFactoriesToTest()
+ throws NoSuchAlgorithmException, KeyManagementException {
+ List<Pair<String, SSLSocketFactory>> result =
+ new ArrayList<Pair<String, SSLSocketFactory>>();
+ result.add(Pair.of("default", (SSLSocketFactory) SSLSocketFactory.getDefault()));
+ for (String sslContextProtocol : StandardNames.SSL_CONTEXT_PROTOCOLS) {
+ SSLContext sslContext = SSLContext.getInstance(sslContextProtocol);
+ if (StandardNames.SSL_CONTEXT_PROTOCOLS_DEFAULT.equals(sslContextProtocol)) {
+ continue;
+ }
+ sslContext.init(null, null, null);
+ result.add(Pair.of(
+ "SSLContext(\"" + sslContext.getProtocol() + "\")",
+ sslContext.getSocketFactory()));
+ }
+ return result;
+ }
+
+ private ClientHello captureTlsHandshakeClientHello(SSLSocketFactory sslSocketFactory)
+ throws Exception {
+ TlsRecord record = captureTlsHandshakeFirstTlsRecord(sslSocketFactory);
+ assertEquals("TLS record type", TlsProtocols.HANDSHAKE, record.type);
+ ByteArrayInputStream fragmentIn = new ByteArrayInputStream(record.fragment);
+ HandshakeMessage handshakeMessage = HandshakeMessage.read(new DataInputStream(fragmentIn));
+ assertEquals("HandshakeMessage type",
+ HandshakeMessage.TYPE_CLIENT_HELLO, handshakeMessage.type);
+ // Assert that the fragment does not contain any more messages
+ assertEquals(0, fragmentIn.available());
+
+ return (ClientHello) handshakeMessage;
+ }
+
+ private TlsRecord captureTlsHandshakeFirstTlsRecord(SSLSocketFactory sslSocketFactory)
+ throws Exception {
+ byte[] firstReceivedChunk = captureTlsHandshakeFirstTransmittedChunkBytes(sslSocketFactory);
+ ByteArrayInputStream firstReceivedChunkIn = new ByteArrayInputStream(firstReceivedChunk);
+ TlsRecord record = TlsRecord.read(new DataInputStream(firstReceivedChunkIn));
+ // Assert that the chunk does not contain any more data
+ assertEquals(0, firstReceivedChunkIn.available());
+
+ return record;
+ }
+
+ private byte[] captureTlsHandshakeFirstTransmittedChunkBytes(
+ final SSLSocketFactory sslSocketFactory) throws Exception {
// Since there's no straightforward way to obtain a ClientHello from SSLSocket, this test
// does the following:
// 1. Creates a listening server socket (a plain one rather than a TLS/SSL one).
@@ -1506,61 +1690,31 @@ public class SSLSocketTest extends TestCase {
executorService.submit(new Callable<Void>() {
@Override
public Void call() throws Exception {
- SSLContext sslContext = SSLContext.getInstance("TLS");
- sslContext.init(null, null, null);
- SSLSocket client = (SSLSocket) sslContext.getSocketFactory().createSocket();
+ Socket client = new Socket();
sockets[0] = client;
try {
- // Enable SNI extension on the socket (this is typically enabled by default)
- // to increase the size of ClientHello.
- try {
- Method setHostname =
- client.getClass().getMethod("setHostname", String.class);
- setHostname.invoke(client, "sslsockettest.androidcts.google.com");
- } catch (NoSuchMethodException ignored) {}
-
- // Enable Session Tickets extension on the socket (this is typically enabled
- // by default) to increase the size of ClientHello.
- try {
- Method setUseSessionTickets =
- client.getClass().getMethod(
- "setUseSessionTickets", boolean.class);
- setUseSessionTickets.invoke(client, true);
- } catch (NoSuchMethodException ignored) {}
-
client.connect(finalListeningSocket.getLocalSocketAddress());
// Initiate the TLS/SSL handshake which is expected to fail as soon as the
// server socket receives a ClientHello.
try {
- client.startHandshake();
+ SSLSocket sslSocket = (SSLSocket) sslSocketFactory.createSocket(
+ client,
+ "localhost.localdomain",
+ finalListeningSocket.getLocalPort(),
+ true);
+ sslSocket.startHandshake();
fail();
return null;
} catch (IOException expected) {}
return null;
} finally {
IoUtils.closeQuietly(client);
-
- // Cancel the reading task. If this task succeeded, then the reading task
- // is done and this will have no effect. If this task failed prematurely,
- // then the reading task might get unblocked (we're interrupting the thread
- // it's running on), will fail early, and we'll thus save some time in this
- // test.
- readFirstReceivedChunkFuture.cancel(true);
}
}
});
// Wait for the ClientHello to arrive
- byte[] clientHello = readFirstReceivedChunkFuture.get(10, TimeUnit.SECONDS);
-
- // Check for ClientHello length that may cause handshake to fail/time out with older
- // F5/BIG-IP appliances.
- assertEquals("TLS record type: handshake", 22, clientHello[0]);
- int fragmentLength = ((clientHello[3] & 0xff) << 8) | (clientHello[4] & 0xff);
- if ((fragmentLength >= 256) && (fragmentLength <= 511)) {
- fail("Fragment containing ClientHello is of dangerous length: "
- + fragmentLength + " bytes");
- }
+ return readFirstReceivedChunkFuture.get(10, TimeUnit.SECONDS);
} finally {
executorService.shutdownNow();
IoUtils.closeQuietly(listeningSocket);
@@ -1668,6 +1822,11 @@ public class SSLSocketTest extends TestCase {
context.close();
}
+ private static void assertInappropriateFallbackIsCause(Throwable cause) {
+ assertTrue(cause.getMessage(), cause.getMessage().contains("inappropriate fallback")
+ || cause.getMessage().contains("INAPPROPRIATE_FALLBACK"));
+ }
+
public void test_SSLSocket_sendsTlsFallbackScsv_InappropriateFallback_Failure() throws Exception {
TestSSLContext context = TestSSLContext.create();
@@ -1693,8 +1852,7 @@ public class SSLSocketTest extends TestCase {
} catch (SSLHandshakeException expected) {
Throwable cause = expected.getCause();
assertEquals(SSLProtocolException.class, cause.getClass());
- assertTrue(cause.getMessage(),
- cause.getMessage().contains("inappropriate fallback"));
+ assertInappropriateFallbackIsCause(cause);
}
return null;
}
@@ -1709,8 +1867,7 @@ public class SSLSocketTest extends TestCase {
} catch (SSLHandshakeException expected) {
Throwable cause = expected.getCause();
assertEquals(SSLProtocolException.class, cause.getClass());
- assertTrue(cause.getMessage(),
- cause.getMessage().contains("inappropriate fallback"));
+ assertInappropriateFallbackIsCause(cause);
}
return null;
}
diff --git a/luni/src/test/java/libcore/net/MimeUtilsTest.java b/luni/src/test/java/libcore/net/MimeUtilsTest.java
index 9bfb375..ff22632 100644
--- a/luni/src/test/java/libcore/net/MimeUtilsTest.java
+++ b/luni/src/test/java/libcore/net/MimeUtilsTest.java
@@ -27,6 +27,12 @@ public class MimeUtilsTest extends TestCase {
assertEquals("flac", MimeUtils.guessExtensionFromMimeType("application/x-flac"));
}
+ // https://code.google.com/p/android/issues/detail?id=78909
+ public void test_78909() {
+ assertEquals("mka", MimeUtils.guessExtensionFromMimeType("audio/x-matroska"));
+ assertEquals("mkv", MimeUtils.guessExtensionFromMimeType("video/x-matroska"));
+ }
+
public void test_16978217() {
assertEquals("image/x-ms-bmp", MimeUtils.guessMimeTypeFromExtension("bmp"));
assertEquals("image/x-icon", MimeUtils.guessMimeTypeFromExtension("ico"));
diff --git a/luni/src/test/java/libcore/net/NetworkSecurityPolicyTest.java b/luni/src/test/java/libcore/net/NetworkSecurityPolicyTest.java
new file mode 100644
index 0000000..d04e2ba
--- /dev/null
+++ b/luni/src/test/java/libcore/net/NetworkSecurityPolicyTest.java
@@ -0,0 +1,315 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package libcore.net;
+
+import junit.framework.TestCase;
+import libcore.io.IoUtils;
+import java.io.Closeable;
+import java.io.IOException;
+import java.net.JarURLConnection;
+import java.net.ServerSocket;
+import java.net.Socket;
+import java.net.URL;
+import java.util.Arrays;
+import java.util.concurrent.Callable;
+import java.util.concurrent.Future;
+import java.util.concurrent.FutureTask;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+import java.util.logging.ErrorManager;
+import java.util.logging.Level;
+import java.util.logging.LogRecord;
+import java.util.logging.SocketHandler;
+
+public class NetworkSecurityPolicyTest extends TestCase {
+
+ private boolean mCleartextTrafficPermittedOriginalState;
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ mCleartextTrafficPermittedOriginalState =
+ NetworkSecurityPolicy.isCleartextTrafficPermitted();
+ }
+
+ @Override
+ protected void tearDown() throws Exception {
+ try {
+ NetworkSecurityPolicy.setCleartextTrafficPermitted(
+ mCleartextTrafficPermittedOriginalState);
+ } finally {
+ super.tearDown();
+ }
+ }
+
+ public void testCleartextTrafficPolicySetterAndGetter() {
+ NetworkSecurityPolicy.setCleartextTrafficPermitted(false);
+ assertEquals(false, NetworkSecurityPolicy.isCleartextTrafficPermitted());
+
+ NetworkSecurityPolicy.setCleartextTrafficPermitted(true);
+ assertEquals(true, NetworkSecurityPolicy.isCleartextTrafficPermitted());
+
+ NetworkSecurityPolicy.setCleartextTrafficPermitted(false);
+ assertEquals(false, NetworkSecurityPolicy.isCleartextTrafficPermitted());
+
+ NetworkSecurityPolicy.setCleartextTrafficPermitted(true);
+ assertEquals(true, NetworkSecurityPolicy.isCleartextTrafficPermitted());
+ }
+
+ public void testCleartextTrafficPolicyWithHttpURLConnection() throws Exception {
+ // Assert that client transmits some data when cleartext traffic is permitted.
+ NetworkSecurityPolicy.setCleartextTrafficPermitted(true);
+ try (CapturingServerSocket server = new CapturingServerSocket()) {
+ URL url = new URL("http://localhost:" + server.getPort() + "/test.txt");
+ try {
+ url.openConnection().getContent();
+ fail();
+ } catch (IOException expected) {
+ }
+ server.assertDataTransmittedByClient();
+ }
+
+ // Assert that client does not transmit any data when cleartext traffic is not permitted and
+ // that URLConnection.openConnection or getContent fail with an IOException.
+ NetworkSecurityPolicy.setCleartextTrafficPermitted(false);
+ try (CapturingServerSocket server = new CapturingServerSocket()) {
+ URL url = new URL("http://localhost:" + server.getPort() + "/test.txt");
+ try {
+ url.openConnection().getContent();
+ fail();
+ } catch (IOException expected) {
+ }
+ server.assertNoDataTransmittedByClient();
+ }
+ }
+
+ public void testCleartextTrafficPolicyWithFtpURLConnection() throws Exception {
+ // Assert that client transmits some data when cleartext traffic is permitted.
+ NetworkSecurityPolicy.setCleartextTrafficPermitted(true);
+ byte[] serverReplyOnConnect = "220\r\n".getBytes("US-ASCII");
+ try (CapturingServerSocket server = new CapturingServerSocket(serverReplyOnConnect)) {
+ URL url = new URL("ftp://localhost:" + server.getPort() + "/test.txt");
+ try {
+ url.openConnection().getContent();
+ fail();
+ } catch (IOException expected) {
+ }
+ server.assertDataTransmittedByClient();
+ }
+
+ // Assert that client does not transmit any data when cleartext traffic is not permitted and
+ // that URLConnection.openConnection or getContent fail with an IOException.
+ NetworkSecurityPolicy.setCleartextTrafficPermitted(false);
+ try (CapturingServerSocket server = new CapturingServerSocket(serverReplyOnConnect)) {
+ URL url = new URL("ftp://localhost:" + server.getPort() + "/test.txt");
+ try {
+ url.openConnection().getContent();
+ fail();
+ } catch (IOException expected) {
+ }
+ server.assertNoDataTransmittedByClient();
+ }
+ }
+
+ public void testCleartextTrafficPolicyWithJarHttpURLConnection() throws Exception {
+ // Assert that client transmits some data when cleartext traffic is permitted.
+ NetworkSecurityPolicy.setCleartextTrafficPermitted(true);
+ try (CapturingServerSocket server = new CapturingServerSocket()) {
+ URL url = new URL("jar:http://localhost:" + server.getPort() + "/test.jar!/");
+ try {
+ ((JarURLConnection) url.openConnection()).getManifest();
+ fail();
+ } catch (IOException expected) {
+ }
+ server.assertDataTransmittedByClient();
+ }
+
+ // Assert that client does not transmit any data when cleartext traffic is not permitted and
+ // that JarURLConnection.openConnection or getManifest fail with an IOException.
+ NetworkSecurityPolicy.setCleartextTrafficPermitted(false);
+ try (CapturingServerSocket server = new CapturingServerSocket()) {
+ URL url = new URL("jar:http://localhost:" + server.getPort() + "/test.jar!/");
+ try {
+ ((JarURLConnection) url.openConnection()).getManifest();
+ fail();
+ } catch (IOException expected) {
+ }
+ server.assertNoDataTransmittedByClient();
+ }
+ }
+
+ public void testCleartextTrafficPolicyWithJarFtpURLConnection() throws Exception {
+ // Assert that client transmits some data when cleartext traffic is permitted.
+ NetworkSecurityPolicy.setCleartextTrafficPermitted(true);
+ byte[] serverReplyOnConnect = "220\r\n".getBytes("US-ASCII");
+ try (CapturingServerSocket server = new CapturingServerSocket(serverReplyOnConnect)) {
+ URL url = new URL("jar:ftp://localhost:" + server.getPort() + "/test.jar!/");
+ try {
+ ((JarURLConnection) url.openConnection()).getManifest();
+ fail();
+ } catch (IOException expected) {
+ }
+ server.assertDataTransmittedByClient();
+ }
+
+ // Assert that client does not transmit any data when cleartext traffic is not permitted and
+ // that JarURLConnection.openConnection or getManifest fail with an IOException.
+ NetworkSecurityPolicy.setCleartextTrafficPermitted(false);
+ try (CapturingServerSocket server = new CapturingServerSocket(serverReplyOnConnect)) {
+ URL url = new URL("jar:ftp://localhost:" + server.getPort() + "/test.jar!/");
+ try {
+ ((JarURLConnection) url.openConnection()).getManifest();
+ fail();
+ } catch (IOException expected) {
+ }
+ server.assertNoDataTransmittedByClient();
+ }
+ }
+
+ public void testCleartextTrafficPolicyWithLoggingSocketHandler() throws Exception {
+ // Assert that client transmits some data when cleartext traffic is permitted.
+ NetworkSecurityPolicy.setCleartextTrafficPermitted(true);
+ try (CapturingServerSocket server = new CapturingServerSocket()) {
+ SocketHandler logger = new SocketHandler("localhost", server.getPort());
+ MockErrorManager mockErrorManager = new MockErrorManager();
+ logger.setErrorManager(mockErrorManager);
+ logger.setLevel(Level.ALL);
+ LogRecord record = new LogRecord(Level.INFO, "A log record");
+ assertTrue(logger.isLoggable(record));
+ logger.publish(record);
+ assertNull(mockErrorManager.getMostRecentException());
+ server.assertDataTransmittedByClient();
+ }
+
+ // Assert that client does not transmit any data when cleartext traffic is not permitted.
+ NetworkSecurityPolicy.setCleartextTrafficPermitted(false);
+ try (CapturingServerSocket server = new CapturingServerSocket()) {
+ try {
+ new SocketHandler("localhost", server.getPort());
+ fail();
+ } catch (IOException expected) {
+ }
+ server.assertNoDataTransmittedByClient();
+ }
+ }
+
+ /**
+ * Server socket which listens on a local port and captures the first chunk of data transmitted
+ * by the client.
+ */
+ private static class CapturingServerSocket implements Closeable {
+ private final ServerSocket mSocket;
+ private final int mPort;
+ private final Thread mListeningThread;
+ private final FutureTask<byte[]> mFirstChunkReceivedFuture;
+
+ /**
+ * Constructs a new socket listening on a local port.
+ */
+ public CapturingServerSocket() throws IOException {
+ this(null);
+ }
+
+ /**
+ * Constructs a new socket listening on a local port, which sends the provided reply as
+ * soon as a client connects to it.
+ */
+ public CapturingServerSocket(final byte[] replyOnConnect) throws IOException {
+ mSocket = new ServerSocket(0);
+ mPort = mSocket.getLocalPort();
+ mFirstChunkReceivedFuture = new FutureTask<byte[]>(new Callable<byte[]>() {
+ @Override
+ public byte[] call() throws Exception {
+ try (Socket client = mSocket.accept()) {
+ // Reply (if requested)
+ if (replyOnConnect != null) {
+ client.getOutputStream().write(replyOnConnect);
+ client.getOutputStream().flush();
+ }
+
+ // Read request
+ byte[] buf = new byte[64 * 1024];
+ int chunkSize = client.getInputStream().read(buf);
+ if (chunkSize == -1) {
+ // Connection closed without any data received
+ return new byte[0];
+ }
+ // Received some data
+ return Arrays.copyOf(buf, chunkSize);
+ } finally {
+ IoUtils.closeQuietly(mSocket);
+ }
+ }
+ });
+ mListeningThread = new Thread(mFirstChunkReceivedFuture);
+ mListeningThread.start();
+ }
+
+ public int getPort() {
+ return mPort;
+ }
+
+ public Future<byte[]> getFirstReceivedChunkFuture() {
+ return mFirstChunkReceivedFuture;
+ }
+
+ @Override
+ public void close() {
+ IoUtils.closeQuietly(mSocket);
+ mListeningThread.interrupt();
+ }
+
+ private void assertDataTransmittedByClient()
+ throws Exception {
+ byte[] firstChunkFromClient = getFirstReceivedChunkFuture().get(2, TimeUnit.SECONDS);
+ if ((firstChunkFromClient == null) || (firstChunkFromClient.length == 0)) {
+ fail("Client did not transmit any data to server");
+ }
+ }
+
+ private void assertNoDataTransmittedByClient()
+ throws Exception {
+ byte[] firstChunkFromClient;
+ try {
+ firstChunkFromClient = getFirstReceivedChunkFuture().get(2, TimeUnit.SECONDS);
+ } catch (TimeoutException expected) {
+ return;
+ }
+ if ((firstChunkFromClient != null) && (firstChunkFromClient.length > 0)) {
+ fail("Client transmitted " + firstChunkFromClient.length+ " bytes: "
+ + new String(firstChunkFromClient, "US-ASCII"));
+ }
+ }
+ }
+
+ private static class MockErrorManager extends ErrorManager {
+ private Exception mMostRecentException;
+
+ public Exception getMostRecentException() {
+ synchronized (this) {
+ return mMostRecentException;
+ }
+ }
+
+ @Override
+ public void error(String message, Exception exception, int errorCode) {
+ synchronized (this) {
+ mMostRecentException = exception;
+ }
+ }
+ }
+}
diff --git a/luni/src/test/java/libcore/net/http/ResponseUtilsTest.java b/luni/src/test/java/libcore/net/http/ResponseUtilsTest.java
new file mode 100644
index 0000000..16745ee
--- /dev/null
+++ b/luni/src/test/java/libcore/net/http/ResponseUtilsTest.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package libcore.net.http;
+
+import java.nio.charset.StandardCharsets;
+import java.nio.charset.UnsupportedCharsetException;
+import junit.framework.TestCase;
+import static libcore.net.http.ResponseUtils.responseCharset;
+
+public class ResponseUtilsTest extends TestCase {
+ public void test_responseCharset_missing() {
+ assertEquals(StandardCharsets.UTF_8, responseCharset(null));
+ assertEquals(StandardCharsets.UTF_8, responseCharset("text/plain"));
+ assertEquals(StandardCharsets.UTF_8, responseCharset("text/plain;foo=bar;baz=bal"));
+ assertEquals(StandardCharsets.UTF_8, responseCharset("text/plain;charset="));
+ }
+
+ public void test_responseCharset_valid() {
+ assertEquals(StandardCharsets.ISO_8859_1,
+ responseCharset("text/plain;charset=ISO-8859-1"));
+ assertEquals(StandardCharsets.ISO_8859_1,
+ responseCharset("text/plain;CHARSET=ISO-8859-1"));
+ assertEquals(StandardCharsets.ISO_8859_1,
+ responseCharset("text/plain; charset = ISO-8859-1"));
+ assertEquals(StandardCharsets.ISO_8859_1,
+ responseCharset("text/plain; foo=bar;baz=bag;charset=ISO-8859-1"));
+ assertEquals(StandardCharsets.ISO_8859_1,
+ responseCharset("text/plain;charset=ISO-8859-1;;==,=="));
+ }
+
+ public void test_responseCharset_invalid() {
+ try {
+ responseCharset("text/plain;charset=unsupportedCharset");
+ fail();
+ } catch (UnsupportedCharsetException expected) {
+ }
+ }
+}
diff --git a/luni/src/test/java/libcore/util/HexEncodingTest.java b/luni/src/test/java/libcore/util/HexEncodingTest.java
new file mode 100644
index 0000000..f5cfb3e
--- /dev/null
+++ b/luni/src/test/java/libcore/util/HexEncodingTest.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package libcore.util;
+
+import java.nio.charset.StandardCharsets;
+import java.util.Arrays;
+import junit.framework.TestCase;
+import static libcore.util.HexEncoding.decode;
+import static libcore.util.HexEncoding.encode;
+
+public class HexEncodingTest extends TestCase {
+ public void testEncode() {
+ final byte[] avocados = "avocados".getBytes(StandardCharsets.UTF_8);
+
+ assertArraysEqual("61766F6361646F73".toCharArray(), encode(avocados));
+ assertArraysEqual(avocados, decode(encode(avocados), false));
+ // Make sure we can handle lower case hex encodings as well.
+ assertArraysEqual(avocados, decode("61766f6361646f73".toCharArray(), false));
+ }
+
+ public void testDecode_allow4Bit() {
+ assertArraysEqual(new byte[] { 6 }, decode("6".toCharArray(), true));
+ assertArraysEqual(new byte[] { 6, 'v' }, decode("676".toCharArray(), true));
+ }
+
+ public void testDecode_disallow4Bit() {
+ try {
+ decode("676".toCharArray(), false);
+ fail();
+ } catch (IllegalArgumentException expected) {
+ }
+ }
+
+ public void testDecode_invalid() {
+ try {
+ decode("DEADBARD".toCharArray(), false);
+ fail();
+ } catch (IllegalArgumentException expected) {
+ }
+
+ // This demonstrates a difference in behaviour from apache commons : apache
+ // commons uses Character.isDigit and would successfully decode a string with
+ // arabic and devanagari characters.
+ try {
+ decode("६१٧٥٥F6361646F73".toCharArray(), false);
+ fail();
+ } catch (IllegalArgumentException expected) {
+ }
+
+ try {
+ decode("#%6361646F73".toCharArray(), false);
+ fail();
+ } catch (IllegalArgumentException expected) {
+ }
+ }
+
+ private static void assertArraysEqual(char[] lhs, char[] rhs) {
+ assertEquals(new String(lhs), new String(rhs));
+ }
+
+ private static void assertArraysEqual(byte[] lhs, byte[] rhs) {
+ assertEquals(Arrays.toString(lhs), Arrays.toString(rhs));
+ }
+}
diff --git a/luni/src/test/java/libcore/util/ZoneInfoDBTest.java b/luni/src/test/java/libcore/util/ZoneInfoDBTest.java
index 9875647..a90bb8e 100644
--- a/luni/src/test/java/libcore/util/ZoneInfoDBTest.java
+++ b/luni/src/test/java/libcore/util/ZoneInfoDBTest.java
@@ -98,6 +98,13 @@ public class ZoneInfoDBTest extends junit.framework.TestCase {
public void testMakeTimeZone_notFound() throws Exception {
ZoneInfoDB.TzData data = new ZoneInfoDB.TzData(TZDATA_IN_ROOT);
assertNull(data.makeTimeZone("THIS_TZ_DOES_NOT_EXIST"));
+ assertFalse(data.hasTimeZone("THIS_TZ_DOES_NOT_EXIST"));
+ }
+
+ public void testMakeTimeZone_found() throws Exception {
+ ZoneInfoDB.TzData data = new ZoneInfoDB.TzData(TZDATA_IN_ROOT);
+ assertNotNull(data.makeTimeZone("Europe/London"));
+ assertTrue(data.hasTimeZone("Europe/London"));
}
private static String makeCorruptFile() throws Exception {
diff --git a/luni/src/test/java/org/apache/harmony/crypto/tests/javax/crypto/ExemptionMechanismTest.java b/luni/src/test/java/org/apache/harmony/crypto/tests/javax/crypto/ExemptionMechanismTest.java
index 87b2913..17fb127 100644
--- a/luni/src/test/java/org/apache/harmony/crypto/tests/javax/crypto/ExemptionMechanismTest.java
+++ b/luni/src/test/java/org/apache/harmony/crypto/tests/javax/crypto/ExemptionMechanismTest.java
@@ -28,7 +28,6 @@ import java.security.Provider;
import java.security.SecureRandom;
import java.security.spec.AlgorithmParameterSpec;
import java.security.spec.RSAKeyGenParameterSpec;
-import java.util.Vector;
import javax.crypto.ExemptionMechanism;
import javax.crypto.ExemptionMechanismException;
@@ -37,7 +36,6 @@ import javax.crypto.KeyGenerator;
import javax.crypto.ShortBufferException;
import org.apache.harmony.crypto.tests.support.MyExemptionMechanismSpi;
-import org.apache.harmony.crypto.tests.support.MyExemptionMechanismSpi.tmpKey;
import org.apache.harmony.security.tests.support.SpiEngUtils;
import junit.framework.TestCase;
@@ -170,45 +168,6 @@ public class ExemptionMechanismTest extends TestCase {
em.genExemptionBlob(new byte[10], -5);
}
- static boolean flag = false;
-
- class Mock_ExemptionMechanism extends ExemptionMechanism {
- protected Mock_ExemptionMechanism(ExemptionMechanismSpi exmechSpi, Provider provider, String mechanism) {
- super(exmechSpi, provider, mechanism);
- }
-
- @Override
- protected void finalize() {
- flag = true;
- super.finalize();
- }
- }
-
- // Side Effect: Causes OutOfMemoryError to test finalization
- public void test_finalize () {
- Mock_ExemptionMechanism mem = new Mock_ExemptionMechanism(null, null, "Name");
- assertNotNull(mem);
- mem = null;
- assertFalse(flag);
- Vector v = new Vector();
- int capacity;
- try {
- while(true) {
- v.add(this);
- }
- } catch (OutOfMemoryError e) {
- capacity = v.size();
- v = null;
- }
-
- v = new Vector();
- for (int i = 0; i < capacity/2; i++) {
- v.add(this);
- }
- v = null;
- assertTrue(flag);
- }
-
class Mock_ExemptionMechanismSpi extends MyExemptionMechanismSpi {
@Override
protected byte[] engineGenExemptionBlob()
diff --git a/luni/src/test/java/org/apache/harmony/crypto/tests/javax/crypto/MacTest.java b/luni/src/test/java/org/apache/harmony/crypto/tests/javax/crypto/MacTest.java
index ddd0695..48d945b 100644
--- a/luni/src/test/java/org/apache/harmony/crypto/tests/javax/crypto/MacTest.java
+++ b/luni/src/test/java/org/apache/harmony/crypto/tests/javax/crypto/MacTest.java
@@ -76,8 +76,13 @@ public class MacTest extends TestCase {
static {
for (int i = 0; i < validAlgorithmsMac.length; i++) {
- defaultProvider = SpiEngUtils.isSupport(validAlgorithmsMac[i],
- srvMac);
+ try {
+ Mac mac = Mac.getInstance(validAlgorithmsMac[i]);
+ mac.init(new SecretKeySpec(new byte[64], validAlgorithmsMac[i]));
+ defaultProvider = mac.getProvider();
+ } catch (NoSuchAlgorithmException ignored) {
+ } catch (InvalidKeyException ignored) {}
+
DEFSupported = (defaultProvider != null);
if (DEFSupported) {
defaultAlgorithm = validAlgorithmsMac[i];
@@ -100,6 +105,12 @@ public class MacTest extends TestCase {
macList.add(Mac.getInstance(defaultAlgorithm, defaultProvider));
macList.add(Mac.getInstance(defaultAlgorithm, defaultProviderName));
for (Provider p : Security.getProviders("Mac." + defaultAlgorithm)) {
+ // Do not test AndroidKeyStore's Mac. It cannot be initialized without providing an
+ // AndroidKeyStore-backed SecretKey instance. It's OKish not to test here because it's
+ // tested by cts/tests/test/keystore.
+ if (p.getName().startsWith("AndroidKeyStore")) {
+ continue;
+ }
macList.add(Mac.getInstance(defaultAlgorithm, p));
}
return macList.toArray(new Mac[macList.size()]);
@@ -845,6 +856,13 @@ public class MacTest extends TestCase {
byte[] output = null;
byte[] output2 = null;
for (int i = 0; i < providers.length; i++) {
+ // Do not test AndroidKeyStore's Mac. It cannot be initialized without providing an
+ // AndroidKeyStore-backed SecretKey instance. It's OKish not to test here because it's
+ // tested by cts/tests/test/keystore.
+ if (providers[i].getName().startsWith("AndroidKeyStore")) {
+ continue;
+ }
+
System.out.println("provider = " + providers[i].getName());
Mac mac = Mac.getInstance("HmacMD5", providers[i]);
mac.init(key);
@@ -884,6 +902,24 @@ public class MacTest extends TestCase {
public abstract void setup();
}
+ public void testMac_getInstance_DoesNotSupportKeyClass_Success() throws Exception {
+ Provider mockProvider = new MockProvider("MockProvider") {
+ public void setup() {
+ put("Mac.FOO", MockMacSpi.AllKeyTypes.class.getName());
+ put("Mac.FOO SupportedKeyClasses", "None");
+ }
+ };
+
+ Security.addProvider(mockProvider);
+ try {
+ Mac s = Mac.getInstance("FOO", mockProvider);
+ s.init(new MockKey());
+ assertEquals(mockProvider, s.getProvider());
+ } finally {
+ Security.removeProvider(mockProvider.getName());
+ }
+ }
+
public void testMac_getInstance_SuppliedProviderNotRegistered_Success() throws Exception {
Provider mockProvider = new MockProvider("MockProvider") {
public void setup() {
diff --git a/luni/src/test/java/org/apache/harmony/security/tests/java/security/Signature2Test.java b/luni/src/test/java/org/apache/harmony/security/tests/java/security/Signature2Test.java
index ad084e1..22e6795 100644
--- a/luni/src/test/java/org/apache/harmony/security/tests/java/security/Signature2Test.java
+++ b/luni/src/test/java/org/apache/harmony/security/tests/java/security/Signature2Test.java
@@ -478,17 +478,10 @@ public class Signature2Test extends junit.framework.TestCase {
} catch (IllegalArgumentException expected) {
}
- if (StandardNames.IS_RI) {
- try {
- sig.verify(signature, signature.length, 0);
- fail();
- } catch (SignatureException expected) {
- }
- } else {
- // Calling Signature.verify a second time should not throw
- // http://code.google.com/p/android/issues/detail?id=34933
- boolean verified = sig.verify(signature, signature.length, 0);
- assertFalse(verified);
+ try {
+ sig.verify(signature, signature.length, 0);
+ fail();
+ } catch (SignatureException expected) {
}
try {
diff --git a/luni/src/test/java/tests/security/cert/CertificateTest.java b/luni/src/test/java/tests/security/cert/CertificateTest.java
index d13e16b..194bfdb 100644
--- a/luni/src/test/java/tests/security/cert/CertificateTest.java
+++ b/luni/src/test/java/tests/security/cert/CertificateTest.java
@@ -300,17 +300,10 @@ public class MyModifiablePublicKey implements PublicKey {
private Certificate cert;
- private Provider wrongProvider;
-
- private Provider usefulProvider;
-
public void setUp() throws Exception {
super.setUp();
TestUtils.initCertPathSSCertChain();
cert = TestUtils.rootCertificateSS;
- CertificateFactory cf = CertificateFactory.getInstance("X.509");
- wrongProvider = cf.getProvider();
- usefulProvider = Signature.getInstance("SHA1WithRSA").getProvider();
}
/**
@@ -326,8 +319,11 @@ public class MyModifiablePublicKey implements PublicKey {
CertificateException, NoSuchAlgorithmException,
NoSuchProviderException, SignatureException {
+ final Signature sig = Signature.getInstance("SHA1WithRSA");
+ sig.initVerify(cert.getPublicKey());
+ final Provider provider = sig.getProvider();
// real test
- cert.verify(cert.getPublicKey(), usefulProvider.getName());
+ cert.verify(cert.getPublicKey(), provider.getName());
// Exception tests
@@ -342,6 +338,9 @@ public class MyModifiablePublicKey implements PublicKey {
// a new provider, test if it works, then remove it and test if the
// exception is thrown.
//
+ // CertificateFactory cf = CertificateFactory.getInstance("X.509");
+ // Provider wrongProvider = cf.getProvider();
+ //
// Security.removeProvider(wrongProvider.getName());
//
// try {
diff --git a/luni/src/test/java/tests/security/interfaces/DSAPrivateKeyTest.java b/luni/src/test/java/tests/security/interfaces/DSAPrivateKeyTest.java
index 6cebda5..5f4abdd 100644
--- a/luni/src/test/java/tests/security/interfaces/DSAPrivateKeyTest.java
+++ b/luni/src/test/java/tests/security/interfaces/DSAPrivateKeyTest.java
@@ -32,9 +32,7 @@ public class DSAPrivateKeyTest extends TestCase {
*/
public void test_getX() throws Exception {
KeyPairGenerator keyGen = KeyPairGenerator.getInstance("DSA");
- keyGen.initialize(new DSAParameterSpec(Util.P, Util.Q, Util.G),
- new SecureRandom(new MySecureRandomSpi(), null) {
- });
+ keyGen.initialize(new DSAParameterSpec(Util.P, Util.Q, Util.G), new SecureRandom());
KeyPair keyPair = keyGen.generateKeyPair();
DSAPrivateKey key = (DSAPrivateKey) keyPair.getPrivate();
assertNotNull("Invalid X value", key.getX());
diff --git a/luni/src/test/java/tests/security/interfaces/DSAPublicKeyTest.java b/luni/src/test/java/tests/security/interfaces/DSAPublicKeyTest.java
index 9fe4910..09e936d 100644
--- a/luni/src/test/java/tests/security/interfaces/DSAPublicKeyTest.java
+++ b/luni/src/test/java/tests/security/interfaces/DSAPublicKeyTest.java
@@ -42,9 +42,7 @@ public class DSAPublicKeyTest extends TestCase {
// Case 1: check with predefined p, q, g, x
keyGen = KeyPairGenerator.getInstance("DSA");
- keyGen.initialize(new DSAParameterSpec(Util.P, Util.Q, Util.G),
- new SecureRandom(new MySecureRandomSpi(), null) {
- });
+ keyGen.initialize(new DSAParameterSpec(Util.P, Util.Q, Util.G), new SecureRandom());
keys = keyGen.generateKeyPair();
priv = (DSAPrivateKey) keys.getPrivate();
publ = (DSAPublicKey) keys.getPublic();
diff --git a/luni/src/test/native/libcore_io_Memory_test.cpp b/luni/src/test/native/libcore_io_Memory_test.cpp
new file mode 100644
index 0000000..2d95155
--- /dev/null
+++ b/luni/src/test/native/libcore_io_Memory_test.cpp
@@ -0,0 +1,134 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "luni/src/main/native/libcore_io_Memory.cpp"
+
+#include <stdlib.h>
+
+#include <functional>
+
+#include <gtest/gtest.h>
+
+#define ALIGNMENT 8
+
+template<typename T, size_t NUM_ELEMENTS>
+void swap_align_test(void (*swap_func)(T*, const T*, size_t),
+ std::function<void (T*, T*, uint64_t)> init_func) {
+ uint8_t* dst = nullptr;
+ uint8_t* src = nullptr;
+ ASSERT_EQ(0, posix_memalign(reinterpret_cast<void**>(&dst), ALIGNMENT,
+ sizeof(T) * NUM_ELEMENTS + ALIGNMENT));
+ ASSERT_EQ(0, posix_memalign(reinterpret_cast<void**>(&src), ALIGNMENT,
+ sizeof(T) * NUM_ELEMENTS + ALIGNMENT));
+
+ T src_buf[NUM_ELEMENTS];
+ T dst_buf[NUM_ELEMENTS];
+ for (uint64_t i = 0; i < NUM_ELEMENTS; i++) {
+ init_func(&src_buf[i], &dst_buf[i], i);
+ }
+
+ // Vary a few alignments.
+ for (size_t dst_align = 0; dst_align < ALIGNMENT; dst_align++) {
+ T* dst_aligned = reinterpret_cast<T*>(&dst[dst_align]);
+ for (size_t src_align = 0; src_align < ALIGNMENT; src_align++) {
+ T* src_aligned = reinterpret_cast<T*>(&src[src_align]);
+ memset(dst_aligned, 0, sizeof(T) * NUM_ELEMENTS);
+ memcpy(src_aligned, src_buf, sizeof(T) * NUM_ELEMENTS);
+ swap_func(dst_aligned, src_aligned, NUM_ELEMENTS);
+ ASSERT_EQ(0, memcmp(dst_buf, dst_aligned, sizeof(T) * NUM_ELEMENTS))
+ << "Failed at dst align " << dst_align << " src align " << src_align;
+ }
+ }
+ free(dst);
+ free(src);
+}
+
+TEST(libcore, swapShorts_align_test) {
+ // Use an odd number to guarantee that the last 16-bit swap code
+ // is executed.
+ swap_align_test<jshort, 9> (swapShorts, [] (jshort* src, jshort* dst, uint64_t i) {
+ *src = ((2*i) << 8) | (2*(i+1));
+ *dst = (2*i) | ((2*(i+1)) << 8);
+ });
+}
+
+TEST(libcore, swapInts_align_test) {
+ swap_align_test<jint, 10> (swapInts, [] (jint* src, jint* dst, uint64_t i) {
+ *src = ((4*i) << 24) | ((4*(i+1)) << 16) | ((4*(i+2)) << 8) | (4*(i+3));
+ *dst = (4*i) | ((4*(i+1)) << 8) | ((4*(i+2)) << 16) | ((4*(i+3)) << 24);
+ });
+}
+
+TEST(libcore, swapLongs_align_test) {
+ swap_align_test<jlong, 10> (swapLongs, [] (jlong* src, jlong* dst, uint64_t i) {
+ *src = ((8*i) << 56) | ((8*(i+1)) << 48) | ((8*(i+2)) << 40) | ((8*(i+3)) << 32) |
+ ((8*(i+4)) << 24) | ((8*(i+5)) << 16) | ((8*(i+6)) << 8) | (8*(i+7));
+ *dst = (8*i) | ((8*(i+1)) << 8) | ((8*(i+2)) << 16) | ((8*(i+3)) << 24) |
+ ((8*(i+4)) << 32) | ((8*(i+5)) << 40) | ((8*(i+6)) << 48) | ((8*(i+7)) << 56);
+ });
+}
+
+template<typename T>
+void memory_peek_test(T (*peek_func)(JNIEnv*, jclass, jlong), T value) {
+ T* src = nullptr;
+ ASSERT_EQ(0, posix_memalign(reinterpret_cast<void**>(&src), ALIGNMENT,
+ sizeof(T) + ALIGNMENT));
+ for (size_t i = 0; i < ALIGNMENT; i++) {
+ jlong src_aligned = reinterpret_cast<jlong>(src) + i;
+ memcpy(reinterpret_cast<void*>(src_aligned), &value, sizeof(T));
+ T result = peek_func(nullptr, nullptr, src_aligned);
+ ASSERT_EQ(value, result);
+ }
+ free(src);
+}
+
+TEST(libcore, Memory_peekShortNative_align_check) {
+ memory_peek_test<jshort>(Memory_peekShortNative, 0x0102);
+}
+
+TEST(libcore, Memory_peekIntNative_align_check) {
+ memory_peek_test<jint>(Memory_peekIntNative, 0x01020304);
+}
+
+TEST(libcore, Memory_peekLongNative_align_check) {
+ memory_peek_test<jlong>(Memory_peekLongNative, 0x01020405060708ULL);
+}
+
+template<typename T>
+void memory_poke_test(void (*poke_func)(JNIEnv*, jclass, jlong, T), T value) {
+ T* dst = nullptr;
+ ASSERT_EQ(0, posix_memalign(reinterpret_cast<void**>(&dst), ALIGNMENT,
+ sizeof(T) + ALIGNMENT));
+ for(size_t i = 0; i < ALIGNMENT; i++) {
+ memset(dst, 0, sizeof(T) + ALIGNMENT);
+ jlong dst_aligned = reinterpret_cast<jlong>(dst) + i;
+ poke_func(nullptr, nullptr, dst_aligned, value);
+ ASSERT_EQ(0, memcmp(reinterpret_cast<void*>(dst_aligned), &value, sizeof(T)));
+ }
+ free(dst);
+}
+
+TEST(libcore, Memory_pokeShortNative_align_check) {
+ memory_poke_test<jshort>(Memory_pokeShortNative, 0x0102);
+}
+
+TEST(libcore, Memory_pokeIntNative_align_check) {
+ memory_poke_test<jint>(Memory_pokeIntNative, 0x01020304);
+}
+
+TEST(libcore, Memory_pokeLongNative_align_check) {
+ memory_poke_test<jlong>(Memory_pokeLongNative, 0x0102030405060708ULL);
+}
diff --git a/luni/src/test/native/test_openssl_engine.cpp b/luni/src/test/native/test_openssl_engine.cpp
deleted file mode 100644
index 9a0f3b3..0000000
--- a/luni/src/test/native/test_openssl_engine.cpp
+++ /dev/null
@@ -1,132 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "UniquePtr.h"
-
-#include <stdarg.h>
-#include <string.h>
-#include <unistd.h>
-
-#include <openssl/objects.h>
-#include <openssl/engine.h>
-#include <openssl/evp.h>
-#include <openssl/pem.h>
-
-#define DYNAMIC_ENGINE
-#define TEST_ENGINE_ID "javacoretests"
-#define TEST_ENGINE_NAME "libcore test engine"
-
-struct RSA_Delete {
- void operator()(RSA* p) const {
- RSA_free(p);
- }
-};
-typedef UniquePtr<RSA, RSA_Delete> Unique_RSA;
-
-static const char* HMAC_TAG = "-HMAC-";
-static const size_t HMAC_TAG_LEN = strlen(HMAC_TAG);
-
-static EVP_PKEY *test_load_key(ENGINE* e, const char *key_id,
- EVP_PKEY* (*read_func)(BIO*, EVP_PKEY**, pem_password_cb*, void*)) {
- void* data = static_cast<void*>(const_cast<char*>(key_id));
-
- EVP_PKEY *key = NULL;
-
- const size_t key_len = strlen(key_id);
- if (key_len > HMAC_TAG_LEN && !strncmp(key_id, HMAC_TAG, HMAC_TAG_LEN)) {
- key = EVP_PKEY_new_mac_key(EVP_PKEY_HMAC, e, reinterpret_cast<const unsigned char*>(key_id),
- key_len);
- } else {
- BIO* in = BIO_new_mem_buf(data, strlen(key_id));
- if (!in) {
- return NULL;
- }
- key = read_func(in, NULL, 0, NULL);
- BIO_free(in);
-
- if (key != NULL && EVP_PKEY_type(key->type) == EVP_PKEY_RSA) {
- ENGINE_init(e);
-
- Unique_RSA rsa(EVP_PKEY_get1_RSA(key));
- rsa->engine = e;
- rsa->flags |= RSA_FLAG_EXT_PKEY;
- }
- }
-
- return key;
-}
-
-static EVP_PKEY* test_load_privkey(ENGINE* e, const char* key_id, UI_METHOD*, void*) {
- return test_load_key(e, key_id, PEM_read_bio_PrivateKey);
-}
-
-static EVP_PKEY* test_load_pubkey(ENGINE* e, const char* key_id, UI_METHOD*, void*) {
- return test_load_key(e, key_id, PEM_read_bio_PUBKEY);
-}
-
-static const int meths[] = {
- EVP_PKEY_HMAC,
-};
-
-static int pkey_meths(ENGINE*, EVP_PKEY_METHOD** meth, const int** nids, int nid) {
- if (nid == EVP_PKEY_HMAC) {
- *meth = const_cast<EVP_PKEY_METHOD*>(EVP_PKEY_meth_find(nid));
- return 1;
- } else if (nid != 0) {
- return 0;
- }
-
- if (nids != NULL) {
- *nids = meths;
- return 1;
- }
-
- return 0;
-}
-
-static int test_engine_setup(ENGINE* e) {
- if (!ENGINE_set_id(e, TEST_ENGINE_ID)
- || !ENGINE_set_name(e, TEST_ENGINE_NAME)
- || !ENGINE_set_flags(e, 0)
- || !ENGINE_set_RSA(e, RSA_get_default_method())
- || !ENGINE_set_load_privkey_function(e, test_load_privkey)
- || !ENGINE_set_load_pubkey_function(e, test_load_pubkey)
- || !ENGINE_set_pkey_meths(e, pkey_meths)) {
- return 0;
- }
-
- return 1;
-}
-
-static int test_engine_bind_fn(ENGINE *e, const char *id) {
- if (id && (strcmp(id, TEST_ENGINE_ID) != 0)) {
- return 0;
- }
-
- if (!test_engine_setup(e)) {
- return 0;
- }
-
- return 1;
-}
-
-extern "C" {
-#undef OPENSSL_EXPORT
-#define OPENSSL_EXPORT extern __attribute__ ((visibility ("default")))
-
-IMPLEMENT_DYNAMIC_CHECK_FN()
-IMPLEMENT_DYNAMIC_BIND_FN(test_engine_bind_fn)
-};
diff --git a/luni/src/test/resources/META-INF/services/java.nio.charset.spi.CharsetProvider b/luni/src/test/resources/META-INF/services/java.nio.charset.spi.CharsetProvider
new file mode 100644
index 0000000..1a53312
--- /dev/null
+++ b/luni/src/test/resources/META-INF/services/java.nio.charset.spi.CharsetProvider
@@ -0,0 +1 @@
+libcore.java.nio.charset.SettableCharsetProvider
diff --git a/run-libcore-tests b/run-libcore-tests
index 79c4d07..fa5a33c 100755
--- a/run-libcore-tests
+++ b/run-libcore-tests
@@ -23,5 +23,7 @@ $VOGAR \
--vm-arg -Xmx32M \
--classpath out/target/common/obj/JAVA_LIBRARIES/core-tests_intermediates/javalib.jar \
--classpath out/target/common/obj/JAVA_LIBRARIES/sqlite-jdbc_intermediates/classes.jar \
+ --classpath out/target/common/obj/JAVA_LIBRARIES/bouncycastle_intermediates/classes.jar \
+ --classpath out/target/common/obj/JAVA_LIBRARIES/okhttp_intermediates/classes.jar \
$test_packages \
|| true
diff --git a/support/src/test/java/libcore/java/security/StandardNames.java b/support/src/test/java/libcore/java/security/StandardNames.java
index 528a651..cfd519a 100644
--- a/support/src/test/java/libcore/java/security/StandardNames.java
+++ b/support/src/test/java/libcore/java/security/StandardNames.java
@@ -101,6 +101,9 @@ public final class StandardNames extends Assert {
public static final Map<String,Set<String>> CIPHER_PADDINGS
= new HashMap<String,Set<String>>();
+ private static final Map<String, String[]> SSL_CONTEXT_PROTOCOLS_ENABLED
+ = new HashMap<String,String[]>();
+
private static void provide(String type, String algorithm) {
Set<String> algorithms = PROVIDER_ALGORITHMS.get(type);
if (algorithms == null) {
@@ -134,6 +137,18 @@ public final class StandardNames extends Assert {
}
paddings.addAll(Arrays.asList(newPaddings));
}
+ private static void provideSslContextEnabledProtocols(String algorithm, TLSVersion minimum,
+ TLSVersion maximum) {
+ if (minimum.ordinal() > maximum.ordinal()) {
+ throw new RuntimeException("TLS version: minimum > maximum");
+ }
+ int versionsLength = maximum.ordinal() - minimum.ordinal() + 1;
+ String[] versionNames = new String[versionsLength];
+ for (int i = 0; i < versionsLength; i++) {
+ versionNames[i] = TLSVersion.values()[i + minimum.ordinal()].name;
+ }
+ SSL_CONTEXT_PROTOCOLS_ENABLED.put(algorithm, versionNames);
+ }
static {
provide("AlgorithmParameterGenerator", "DSA");
provide("AlgorithmParameterGenerator", "DiffieHellman");
@@ -165,7 +180,6 @@ public final class StandardNames extends Assert {
provide("Cipher", "DES");
provide("Cipher", "DESede");
provide("Cipher", "DESedeWrap");
- provide("Cipher", "GCM");
provide("Cipher", "PBEWithMD5AndDES");
provide("Cipher", "PBEWithMD5AndTripleDES");
provide("Cipher", "PBEWithSHA1AndDESede");
@@ -379,6 +393,23 @@ public final class StandardNames extends Assert {
provide("Signature", "NONEwithRSA");
provide("Cipher", "RSA/ECB/NOPADDING");
provide("Cipher", "RSA/ECB/PKCS1PADDING");
+ provide("Cipher", "RSA/ECB/OAEPPadding");
+ provide("Cipher", "RSA/ECB/OAEPWithSHA-1AndMGF1Padding");
+ provide("Cipher", "RSA/ECB/OAEPWithSHA-224AndMGF1Padding");
+ provide("Cipher", "RSA/ECB/OAEPWithSHA-256AndMGF1Padding");
+ provide("Cipher", "RSA/ECB/OAEPWithSHA-384AndMGF1Padding");
+ provide("Cipher", "RSA/ECB/OAEPWithSHA-512AndMGF1Padding");
+ provide("SecretKeyFactory", "AES");
+ provide("SecretKeyFactory", "HmacSHA1");
+ provide("SecretKeyFactory", "HmacSHA224");
+ provide("SecretKeyFactory", "HmacSHA256");
+ provide("SecretKeyFactory", "HmacSHA384");
+ provide("SecretKeyFactory", "HmacSHA512");
+ provide("Signature", "SHA1withRSA/PSS");
+ provide("Signature", "SHA224withRSA/PSS");
+ provide("Signature", "SHA256withRSA/PSS");
+ provide("Signature", "SHA384withRSA/PSS");
+ provide("Signature", "SHA512withRSA/PSS");
// different names: ARCFOUR vs ARC4
unprovide("Cipher", "ARCFOUR");
@@ -458,6 +489,7 @@ public final class StandardNames extends Assert {
provide("Cipher", "AES/ECB/NOPADDING");
provide("Cipher", "AES/ECB/PKCS5PADDING");
provide("Cipher", "AES/ECB/PKCS7PADDING");
+ provide("Cipher", "AES/GCM/NOPADDING");
provide("Cipher", "AES/OFB/NOPADDING");
provide("Cipher", "AES/OFB/PKCS5PADDING");
provide("Cipher", "AES/OFB/PKCS7PADDING");
@@ -533,6 +565,24 @@ public final class StandardNames extends Assert {
}
}
+
+ if (IS_RI) {
+ provideSslContextEnabledProtocols("SSL", TLSVersion.SSLv3, TLSVersion.TLSv1);
+ provideSslContextEnabledProtocols("SSLv3", TLSVersion.SSLv3, TLSVersion.TLSv1);
+ provideSslContextEnabledProtocols("TLS", TLSVersion.SSLv3, TLSVersion.TLSv1);
+ provideSslContextEnabledProtocols("TLSv1", TLSVersion.SSLv3, TLSVersion.TLSv1);
+ provideSslContextEnabledProtocols("TLSv1.1", TLSVersion.SSLv3, TLSVersion.TLSv11);
+ provideSslContextEnabledProtocols("TLSv1.2", TLSVersion.SSLv3, TLSVersion.TLSv12);
+ provideSslContextEnabledProtocols("Default", TLSVersion.SSLv3, TLSVersion.TLSv1);
+ } else {
+ provideSslContextEnabledProtocols("SSL", TLSVersion.SSLv3, TLSVersion.TLSv12);
+ provideSslContextEnabledProtocols("SSLv3", TLSVersion.SSLv3, TLSVersion.TLSv12);
+ provideSslContextEnabledProtocols("TLS", TLSVersion.TLSv1, TLSVersion.TLSv12);
+ provideSslContextEnabledProtocols("TLSv1", TLSVersion.TLSv1, TLSVersion.TLSv12);
+ provideSslContextEnabledProtocols("TLSv1.1", TLSVersion.TLSv1, TLSVersion.TLSv12);
+ provideSslContextEnabledProtocols("TLSv1.2", TLSVersion.TLSv1, TLSVersion.TLSv12);
+ provideSslContextEnabledProtocols("Default", TLSVersion.TLSv1, TLSVersion.TLSv12);
+ }
}
public static final String SSL_CONTEXT_PROTOCOLS_DEFAULT = "Default";
@@ -571,13 +621,11 @@ public final class StandardNames extends Assert {
"TLSv1.2"));
public static final Set<String> SSL_SOCKET_PROTOCOLS_CLIENT_DEFAULT =
new HashSet<String>(Arrays.asList(
- "SSLv3",
"TLSv1",
"TLSv1.1",
"TLSv1.2"));
public static final Set<String> SSL_SOCKET_PROTOCOLS_SERVER_DEFAULT =
new HashSet<String>(Arrays.asList(
- "SSLv3",
"TLSv1",
"TLSv1.1",
"TLSv1.2"));
@@ -590,9 +638,26 @@ public final class StandardNames extends Assert {
* do to disable general use of SSLv2.
*/
SSL_SOCKET_PROTOCOLS.add("SSLv2Hello");
+
+ /* The RI still has SSLv3 as a default protocol. */
+ SSL_SOCKET_PROTOCOLS_CLIENT_DEFAULT.add("SSLv3");
+ SSL_SOCKET_PROTOCOLS_SERVER_DEFAULT.add("SSLv3");
}
}
+ private static enum TLSVersion {
+ SSLv3("SSLv3"),
+ TLSv1("TLSv1"),
+ TLSv11("TLSv1.1"),
+ TLSv12("TLSv1.2");
+
+ private final String name;
+
+ TLSVersion(String name) {
+ this.name = name;
+ }
+ };
+
/**
* Valid values for X509TrustManager.checkClientTrusted authType,
* either the algorithm of the public key or UNKNOWN.
@@ -660,33 +725,18 @@ public final class StandardNames extends Assert {
addBoth( "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA");
addBoth( "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA");
addBoth( "TLS_RSA_WITH_AES_256_CBC_SHA");
- addBoth( "TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA");
- addBoth( "TLS_ECDH_RSA_WITH_AES_256_CBC_SHA");
addBoth( "TLS_DHE_RSA_WITH_AES_256_CBC_SHA");
- addBoth( "TLS_DHE_DSS_WITH_AES_256_CBC_SHA");
addBoth( "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA");
addBoth( "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA");
addBoth( "TLS_RSA_WITH_AES_128_CBC_SHA");
- addBoth( "TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA");
- addBoth( "TLS_ECDH_RSA_WITH_AES_128_CBC_SHA");
addBoth( "TLS_DHE_RSA_WITH_AES_128_CBC_SHA");
- addBoth( "TLS_DHE_DSS_WITH_AES_128_CBC_SHA");
addBoth( "TLS_ECDHE_ECDSA_WITH_RC4_128_SHA");
addBoth( "TLS_ECDHE_RSA_WITH_RC4_128_SHA");
addBoth( "SSL_RSA_WITH_RC4_128_SHA");
- addBoth( "TLS_ECDH_ECDSA_WITH_RC4_128_SHA");
- addBoth( "TLS_ECDH_RSA_WITH_RC4_128_SHA");
- addBoth( "TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA");
- addBoth( "TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA");
addBoth( "SSL_RSA_WITH_3DES_EDE_CBC_SHA");
- addBoth( "TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA");
- addBoth( "TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA");
- addBoth( "SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA");
- addBoth( "SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA");
addBoth( "SSL_RSA_WITH_RC4_128_MD5");
// TLSv1.2 cipher suites
- addBoth( "TLS_RSA_WITH_NULL_SHA256");
addBoth( "TLS_RSA_WITH_AES_128_CBC_SHA256");
addBoth( "TLS_RSA_WITH_AES_256_CBC_SHA256");
addOpenSsl("TLS_RSA_WITH_AES_128_GCM_SHA256");
@@ -695,18 +745,6 @@ public final class StandardNames extends Assert {
addBoth( "TLS_DHE_RSA_WITH_AES_256_CBC_SHA256");
addOpenSsl("TLS_DHE_RSA_WITH_AES_128_GCM_SHA256");
addOpenSsl("TLS_DHE_RSA_WITH_AES_256_GCM_SHA384");
- addBoth( "TLS_DHE_DSS_WITH_AES_128_CBC_SHA256");
- addBoth( "TLS_DHE_DSS_WITH_AES_256_CBC_SHA256");
- addOpenSsl("TLS_DHE_DSS_WITH_AES_128_GCM_SHA256");
- addOpenSsl("TLS_DHE_DSS_WITH_AES_256_GCM_SHA384");
- addBoth( "TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256");
- addBoth( "TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384");
- addOpenSsl("TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256");
- addOpenSsl("TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384");
- addBoth( "TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256");
- addBoth( "TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384");
- addOpenSsl("TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256");
- addOpenSsl("TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384");
addBoth( "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256");
addBoth( "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384");
addOpenSsl("TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256");
@@ -715,14 +753,9 @@ public final class StandardNames extends Assert {
addBoth( "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384");
addOpenSsl("TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256");
addOpenSsl("TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384");
- addBoth( "TLS_DH_anon_WITH_AES_128_CBC_SHA256");
- addBoth( "TLS_DH_anon_WITH_AES_256_CBC_SHA256");
- addOpenSsl("TLS_DH_anon_WITH_AES_128_GCM_SHA256");
- addOpenSsl("TLS_DH_anon_WITH_AES_256_GCM_SHA384");
// Pre-Shared Key (PSK) cipher suites
addOpenSsl("TLS_PSK_WITH_RC4_128_SHA");
- addOpenSsl("TLS_PSK_WITH_3DES_EDE_CBC_SHA");
addOpenSsl("TLS_PSK_WITH_AES_128_CBC_SHA");
addOpenSsl("TLS_PSK_WITH_AES_256_CBC_SHA");
addOpenSsl("TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA");
@@ -736,33 +769,8 @@ public final class StandardNames extends Assert {
addOpenSsl(CIPHER_SUITE_FALLBACK);
// non-defaultCipherSuites
- addBoth( "TLS_ECDH_anon_WITH_AES_256_CBC_SHA");
- addBoth( "TLS_DH_anon_WITH_AES_256_CBC_SHA");
- addBoth( "TLS_ECDH_anon_WITH_AES_128_CBC_SHA");
- addBoth( "TLS_DH_anon_WITH_AES_128_CBC_SHA");
- addBoth( "TLS_ECDH_anon_WITH_RC4_128_SHA");
- addBoth( "SSL_DH_anon_WITH_RC4_128_MD5");
- addBoth( "TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA");
- addBoth( "SSL_DH_anon_WITH_3DES_EDE_CBC_SHA");
- addBoth( "TLS_ECDHE_ECDSA_WITH_NULL_SHA");
- addBoth( "TLS_ECDHE_RSA_WITH_NULL_SHA");
- addBoth( "SSL_RSA_WITH_NULL_SHA");
- addBoth( "TLS_ECDH_ECDSA_WITH_NULL_SHA");
- addBoth( "TLS_ECDH_RSA_WITH_NULL_SHA");
- addBoth( "TLS_ECDH_anon_WITH_NULL_SHA");
- addBoth( "SSL_RSA_WITH_NULL_MD5");
- addBoth( "SSL_RSA_WITH_DES_CBC_SHA");
- addBoth( "SSL_DHE_RSA_WITH_DES_CBC_SHA");
- addBoth( "SSL_DHE_DSS_WITH_DES_CBC_SHA");
- addBoth( "SSL_DH_anon_WITH_DES_CBC_SHA");
- addBoth( "SSL_RSA_EXPORT_WITH_RC4_40_MD5");
- addBoth( "SSL_DH_anon_EXPORT_WITH_RC4_40_MD5");
- addBoth( "SSL_RSA_EXPORT_WITH_DES40_CBC_SHA");
- addBoth( "SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA");
- addBoth( "SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA");
- addBoth( "SSL_DH_anon_EXPORT_WITH_DES40_CBC_SHA");
-
- // Android does not have Keberos support
+
+ // Android does not have Kerberos support
addRi( "TLS_KRB5_WITH_RC4_128_SHA");
addRi( "TLS_KRB5_WITH_RC4_128_MD5");
addRi( "TLS_KRB5_WITH_3DES_EDE_CBC_SHA");
@@ -774,9 +782,68 @@ public final class StandardNames extends Assert {
addRi( "TLS_KRB5_EXPORT_WITH_DES_CBC_40_SHA");
addRi( "TLS_KRB5_EXPORT_WITH_DES_CBC_40_MD5");
+ // Android does not have DSS support
+ addRi( "SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA");
+ addRi( "SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA");
+ addRi( "SSL_DHE_DSS_WITH_DES_CBC_SHA");
+ addRi( "TLS_DHE_DSS_WITH_AES_128_CBC_SHA");
+ addRi( "TLS_DHE_DSS_WITH_AES_128_CBC_SHA256");
+ addNeither("TLS_DHE_DSS_WITH_AES_128_GCM_SHA256");
+ addRi( "TLS_DHE_DSS_WITH_AES_256_CBC_SHA");
+ addRi( "TLS_DHE_DSS_WITH_AES_256_CBC_SHA256");
+ addNeither("TLS_DHE_DSS_WITH_AES_256_GCM_SHA384");
+
// Dropped
addNeither("SSL_DH_DSS_EXPORT_WITH_DES40_CBC_SHA");
addNeither("SSL_DH_RSA_EXPORT_WITH_DES40_CBC_SHA");
+ addRi( "SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA");
+ addRi( "SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA");
+ addRi( "SSL_DHE_RSA_WITH_DES_CBC_SHA");
+ addRi( "SSL_DH_anon_EXPORT_WITH_DES40_CBC_SHA");
+ addRi( "SSL_DH_anon_EXPORT_WITH_RC4_40_MD5");
+ addRi( "SSL_DH_anon_WITH_3DES_EDE_CBC_SHA");
+ addRi( "SSL_DH_anon_WITH_DES_CBC_SHA");
+ addRi( "SSL_DH_anon_WITH_RC4_128_MD5");
+ addRi( "SSL_RSA_EXPORT_WITH_DES40_CBC_SHA");
+ addRi( "SSL_RSA_EXPORT_WITH_RC4_40_MD5");
+ addRi( "SSL_RSA_WITH_DES_CBC_SHA");
+ addRi( "SSL_RSA_WITH_NULL_MD5");
+ addRi( "SSL_RSA_WITH_NULL_SHA");
+ addRi( "TLS_DH_anon_WITH_AES_128_CBC_SHA");
+ addRi( "TLS_DH_anon_WITH_AES_128_CBC_SHA256");
+ addNeither("TLS_DH_anon_WITH_AES_128_GCM_SHA256");
+ addRi( "TLS_DH_anon_WITH_AES_256_CBC_SHA");
+ addRi( "TLS_DH_anon_WITH_AES_256_CBC_SHA256");
+ addNeither("TLS_DH_anon_WITH_AES_256_GCM_SHA384");
+ addRi( "TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA");
+ addRi( "TLS_ECDHE_ECDSA_WITH_NULL_SHA");
+ addRi( "TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA");
+ addRi( "TLS_ECDHE_RSA_WITH_NULL_SHA");
+ addRi( "TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA");
+ addRi( "TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA");
+ addRi( "TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256");
+ addNeither("TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256");
+ addRi( "TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA");
+ addRi( "TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384");
+ addNeither("TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384");
+ addRi( "TLS_ECDH_ECDSA_WITH_NULL_SHA");
+ addRi( "TLS_ECDH_ECDSA_WITH_RC4_128_SHA");
+ addRi( "TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA");
+ addRi( "TLS_ECDH_RSA_WITH_AES_128_CBC_SHA");
+ addRi( "TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256");
+ addNeither("TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256");
+ addRi( "TLS_ECDH_RSA_WITH_AES_256_CBC_SHA");
+ addRi( "TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384");
+ addNeither("TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384");
+ addRi( "TLS_ECDH_RSA_WITH_NULL_SHA");
+ addRi( "TLS_ECDH_RSA_WITH_RC4_128_SHA");
+ addRi( "TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA");
+ addRi( "TLS_ECDH_anon_WITH_AES_128_CBC_SHA");
+ addRi( "TLS_ECDH_anon_WITH_AES_256_CBC_SHA");
+ addRi( "TLS_ECDH_anon_WITH_NULL_SHA");
+ addRi( "TLS_ECDH_anon_WITH_RC4_128_SHA");
+ addNeither("TLS_PSK_WITH_3DES_EDE_CBC_SHA");
+ addRi( "TLS_RSA_WITH_NULL_SHA256");
// Old non standard exportable encryption
addNeither("SSL_RSA_EXPORT1024_WITH_DES_CBC_SHA");
@@ -864,8 +931,6 @@ public final class StandardNames extends Assert {
"TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA",
"TLS_DHE_RSA_WITH_AES_128_CBC_SHA",
"TLS_DHE_RSA_WITH_AES_256_CBC_SHA",
- "TLS_DHE_DSS_WITH_AES_128_CBC_SHA",
- "TLS_DHE_DSS_WITH_AES_256_CBC_SHA",
"TLS_ECDHE_ECDSA_WITH_RC4_128_SHA",
"TLS_ECDHE_RSA_WITH_RC4_128_SHA",
"TLS_RSA_WITH_AES_128_GCM_SHA256",
@@ -943,7 +1008,8 @@ public final class StandardNames extends Assert {
* suites in a test for those that want to verify separately that
* all cipher suites were included.
*/
- public static Set<String> assertValidCipherSuites(Set<String> expected, String[] cipherSuites) {
+ private static Set<String> assertValidCipherSuites(
+ Set<String> expected, String[] cipherSuites) {
assertNotNull(cipherSuites);
assertTrue(cipherSuites.length != 0);
@@ -965,7 +1031,7 @@ public final class StandardNames extends Assert {
* assertSupportedCipherSuites additionally verifies that all
* supported cipher suites where in the input array.
*/
- public static void assertSupportedCipherSuites(Set<String> expected, String[] cipherSuites) {
+ private static void assertSupportedCipherSuites(Set<String> expected, String[] cipherSuites) {
Set<String> remainingCipherSuites = assertValidCipherSuites(expected, cipherSuites);
assertEquals("Missing cipher suites", Collections.EMPTY_SET, remainingCipherSuites);
assertEquals(expected.size(), cipherSuites.length);
@@ -978,7 +1044,7 @@ public final class StandardNames extends Assert {
* those that want to verify separately that all protocols were
* included.
*/
- public static Set<String> assertValidProtocols(Set<String> expected, String[] protocols) {
+ private static Set<String> assertValidProtocols(Set<String> expected, String[] protocols) {
assertNotNull(protocols);
assertTrue(protocols.length != 0);
@@ -999,21 +1065,13 @@ public final class StandardNames extends Assert {
* assertSupportedProtocols additionally verifies that all
* supported protocols where in the input array.
*/
- public static void assertSupportedProtocols(Set<String> expected, String[] protocols) {
+ private static void assertSupportedProtocols(Set<String> expected, String[] protocols) {
Set<String> remainingProtocols = assertValidProtocols(expected, protocols);
assertEquals("Missing protocols", Collections.EMPTY_SET, remainingProtocols);
assertEquals(expected.size(), protocols.length);
}
/**
- * Asserts that the protocols array is non-null and that all of its contents are supported
- * protocols.
- */
- public static void assertValidProtocols(String[] protocols) {
- assertValidProtocols(SSL_SOCKET_PROTOCOLS, protocols);
- }
-
- /**
* Asserts that the provided list of protocols matches the supported list of protocols.
*/
public static void assertSupportedProtocols(String[] protocols) {
@@ -1021,33 +1079,6 @@ public final class StandardNames extends Assert {
}
/**
- * Asserts that the protocols array contains all the protocols enabled by default for client use
- * and no other ones.
- */
- public static void assertDefaultProtocolsClient(String[] protocols) {
- assertValidProtocols(protocols);
- assertSupportedProtocols(SSL_SOCKET_PROTOCOLS_CLIENT_DEFAULT, protocols);
- }
-
- /**
- * Asserts that the protocols array contains all the protocols enabled by default for server use
- * and no other ones.
- */
- public static void assertDefaultProtocolsServer(String[] protocols) {
- assertValidProtocols(protocols);
- assertSupportedProtocols(SSL_SOCKET_PROTOCOLS_SERVER_DEFAULT, protocols);
- }
-
- /**
- * Asserts that the protocols array contains all the protocols enabled by default for
- * {@link javax.net.ssl.SSLEngine} and no other ones.
- */
- public static void assertSSLEngineDefaultProtocols(String[] protocols) {
- assertValidProtocols(protocols);
- assertSupportedProtocols(SSL_SOCKET_PROTOCOLS_CLIENT_DEFAULT, protocols);
- }
-
- /**
* Assert that the provided list of cipher suites contains only the supported cipher suites.
*/
public static void assertValidCipherSuites(String[] cipherSuites) {
@@ -1084,6 +1115,12 @@ public final class StandardNames extends Assert {
}
}
+ public static void assertSSLContextEnabledProtocols(String version, String[] protocols) {
+ assertEquals("For protocol \"" + version + "\"",
+ Arrays.toString(SSL_CONTEXT_PROTOCOLS_ENABLED.get(version)),
+ Arrays.toString(protocols));
+ }
+
private static boolean isPermittedDefaultCipherSuite(String cipherSuite) {
assertNotNull(cipherSuite);
if (CIPHER_SUITE_SECURE_RENEGOTIATION.equals(cipherSuite)) {
diff --git a/support/src/test/java/libcore/javax/net/ssl/SSLConfigurationAsserts.java b/support/src/test/java/libcore/javax/net/ssl/SSLConfigurationAsserts.java
new file mode 100644
index 0000000..bdaad65
--- /dev/null
+++ b/support/src/test/java/libcore/javax/net/ssl/SSLConfigurationAsserts.java
@@ -0,0 +1,248 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package libcore.javax.net.ssl;
+
+import junit.framework.Assert;
+import libcore.java.security.StandardNames;
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Set;
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLEngine;
+import javax.net.ssl.SSLParameters;
+import javax.net.ssl.SSLServerSocket;
+import javax.net.ssl.SSLServerSocketFactory;
+import javax.net.ssl.SSLSocket;
+import javax.net.ssl.SSLSocketFactory;
+
+/**
+ * Assertions about the configuration of TLS/SSL primitives.
+ */
+public class SSLConfigurationAsserts extends Assert {
+
+ /** Hidden constructor to prevent instantiation. */
+ private SSLConfigurationAsserts() {}
+
+ /**
+ * Asserts that the provided {@link SSLContext} has the expected default configuration, and that
+ * {@link SSLSocketFactory}, {@link SSLServerSocketFactory}, {@link SSLSocket},
+ * {@link SSLServerSocket} and {@link SSLEngine} instances created from the context match the
+ * configuration.
+ */
+ public static void assertSSLContextDefaultConfiguration(SSLContext sslContext)
+ throws IOException {
+ SSLParameters defaultParameters = sslContext.getDefaultSSLParameters();
+ StandardNames.assertSSLContextEnabledProtocols(sslContext.getProtocol(),
+ defaultParameters.getProtocols());
+ StandardNames.assertDefaultCipherSuites(defaultParameters.getCipherSuites());
+ assertFalse(defaultParameters.getWantClientAuth());
+ assertFalse(defaultParameters.getNeedClientAuth());
+
+ SSLParameters supportedParameters = sslContext.getSupportedSSLParameters();
+ StandardNames.assertSupportedCipherSuites(supportedParameters.getCipherSuites());
+ StandardNames.assertSupportedProtocols(supportedParameters.getProtocols());
+ assertFalse(supportedParameters.getWantClientAuth());
+ assertFalse(supportedParameters.getNeedClientAuth());
+
+ assertContainsAll("Unsupported enabled cipher suites", supportedParameters.getCipherSuites(),
+ defaultParameters.getCipherSuites());
+ assertContainsAll("Unsupported enabled protocols", supportedParameters.getProtocols(),
+ defaultParameters.getProtocols());
+
+ assertSSLSocketFactoryConfigSameAsSSLContext(sslContext.getSocketFactory(), sslContext);
+ assertSSLServerSocketFactoryConfigSameAsSSLContext(sslContext.getServerSocketFactory(),
+ sslContext);
+
+ SSLEngine sslEngine = sslContext.createSSLEngine();
+ assertFalse(sslEngine.getUseClientMode());
+ assertSSLEngineConfigSameAsSSLContext(sslEngine, sslContext);
+ }
+
+ /**
+ * Asserts that the provided {@link SSLSocketFactory} has the expected default configuration and
+ * that {@link SSLSocket} instances created by the factory match the configuration.
+ */
+ public static void assertSSLSocketFactoryDefaultConfiguration(
+ SSLSocketFactory sslSocketFactory) throws Exception {
+ assertSSLSocketFactoryConfigSameAsSSLContext(sslSocketFactory,
+ SSLContext.getDefault());
+ }
+
+ /**
+ * Asserts that {@link SSLSocketFactory}'s configuration matches {@code SSLContext}'s
+ * configuration, and that {@link SSLSocket} instances obtained from the factory match this
+ * configuration as well.
+ */
+ private static void assertSSLSocketFactoryConfigSameAsSSLContext(
+ SSLSocketFactory sslSocketFactory, SSLContext sslContext) throws IOException {
+ assertCipherSuitesEqual(sslContext.getDefaultSSLParameters().getCipherSuites(),
+ sslSocketFactory.getDefaultCipherSuites());
+ assertCipherSuitesEqual(sslContext.getSupportedSSLParameters().getCipherSuites(),
+ sslSocketFactory.getSupportedCipherSuites());
+
+ try (SSLSocket sslSocket = (SSLSocket) sslSocketFactory.createSocket()) {
+ assertTrue(sslSocket.getUseClientMode());
+ assertTrue(sslSocket.getEnableSessionCreation());
+ assertSSLSocketConfigSameAsSSLContext(sslSocket, sslContext);
+ }
+ }
+
+ /**
+ * Asserts that the provided {@link SSLSocket} has the expected default configuration.
+ */
+ public static void assertSSLSocketDefaultConfiguration(SSLSocket sslSocket) throws Exception {
+ assertTrue(sslSocket.getUseClientMode());
+ assertTrue(sslSocket.getEnableSessionCreation());
+ assertSSLSocketConfigSameAsSSLContext(sslSocket, SSLContext.getDefault());
+ }
+
+ /**
+ * Asserts that {@link SSLSocket}'s configuration matches {@code SSLContext's} configuration.
+ */
+ private static void assertSSLSocketConfigSameAsSSLContext(SSLSocket sslSocket,
+ SSLContext sslContext) {
+ assertSSLParametersEqual(sslSocket.getSSLParameters(), sslContext.getDefaultSSLParameters());
+ assertCipherSuitesEqual(sslSocket.getEnabledCipherSuites(),
+ sslContext.getDefaultSSLParameters().getCipherSuites());
+ assertProtocolsEqual(sslSocket.getEnabledProtocols(),
+ sslContext.getDefaultSSLParameters().getProtocols());
+
+ assertCipherSuitesEqual(sslSocket.getSupportedCipherSuites(),
+ sslContext.getSupportedSSLParameters().getCipherSuites());
+ assertProtocolsEqual(sslSocket.getSupportedProtocols(),
+ sslContext.getSupportedSSLParameters().getProtocols());
+ }
+
+ /**
+ * Asserts that the provided {@link SSLServerSocketFactory} has the expected default
+ * configuration, and that {@link SSLServerSocket} instances created by the factory match the
+ * configuration.
+ */
+ public static void assertSSLServerSocketFactoryDefaultConfiguration(
+ SSLServerSocketFactory sslServerSocketFactory) throws Exception {
+ assertSSLServerSocketFactoryConfigSameAsSSLContext(sslServerSocketFactory,
+ SSLContext.getDefault());
+ }
+
+ /**
+ * Asserts that {@link SSLServerSocketFactory}'s configuration matches {@code SSLContext}'s
+ * configuration, and that {@link SSLServerSocket} instances obtained from the factory match this
+ * configuration as well.
+ */
+ private static void assertSSLServerSocketFactoryConfigSameAsSSLContext(
+ SSLServerSocketFactory sslServerSocketFactory, SSLContext sslContext) throws IOException {
+ assertCipherSuitesEqual(sslContext.getDefaultSSLParameters().getCipherSuites(),
+ sslServerSocketFactory.getDefaultCipherSuites());
+ assertCipherSuitesEqual(sslContext.getSupportedSSLParameters().getCipherSuites(),
+ sslServerSocketFactory.getSupportedCipherSuites());
+ try (SSLServerSocket sslServerSocket =
+ (SSLServerSocket) sslServerSocketFactory.createServerSocket()) {
+ assertFalse(sslServerSocket.getUseClientMode());
+ assertTrue(sslServerSocket.getEnableSessionCreation());
+ assertSSLServerSocketConfigSameAsSSLContext(sslServerSocket, sslContext);
+ }
+ }
+
+ /**
+ * Asserts that the provided {@link SSLServerSocket} has the expected default configuration.
+ */
+ public static void assertSSLServerSocketDefaultConfiguration(SSLServerSocket sslServerSocket)
+ throws Exception {
+ assertFalse(sslServerSocket.getUseClientMode());
+ assertTrue(sslServerSocket.getEnableSessionCreation());
+ assertSSLServerSocketConfigSameAsSSLContext(sslServerSocket, SSLContext.getDefault());
+ // TODO: Check SSLParameters when supported by SSLServerSocket API
+ }
+
+ /**
+ * Asserts that {@link SSLServerSocket}'s configuration matches {@code SSLContext's}
+ * configuration.
+ */
+ private static void assertSSLServerSocketConfigSameAsSSLContext(SSLServerSocket sslServerSocket,
+ SSLContext sslContext) {
+ assertCipherSuitesEqual(sslServerSocket.getEnabledCipherSuites(),
+ sslContext.getDefaultSSLParameters().getCipherSuites());
+ assertProtocolsEqual(sslServerSocket.getEnabledProtocols(),
+ sslContext.getDefaultSSLParameters().getProtocols());
+
+ assertCipherSuitesEqual(sslServerSocket.getSupportedCipherSuites(),
+ sslContext.getSupportedSSLParameters().getCipherSuites());
+ assertProtocolsEqual(sslServerSocket.getSupportedProtocols(),
+ sslContext.getSupportedSSLParameters().getProtocols());
+
+ assertEquals(sslServerSocket.getNeedClientAuth(),
+ sslContext.getDefaultSSLParameters().getNeedClientAuth());
+ assertEquals(sslServerSocket.getWantClientAuth(),
+ sslContext.getDefaultSSLParameters().getWantClientAuth());
+ }
+
+ /**
+ * Asserts that the provided {@link SSLEngine} has the expected default configuration.
+ */
+ public static void assertSSLEngineDefaultConfiguration(SSLEngine sslEngine) throws Exception {
+ assertFalse(sslEngine.getUseClientMode());
+ assertTrue(sslEngine.getEnableSessionCreation());
+ assertSSLEngineConfigSameAsSSLContext(sslEngine, SSLContext.getDefault());
+ }
+
+ /**
+ * Asserts that {@link SSLEngine}'s configuration matches {@code SSLContext's} configuration.
+ */
+ private static void assertSSLEngineConfigSameAsSSLContext(SSLEngine sslEngine,
+ SSLContext sslContext) {
+ assertSSLParametersEqual(sslEngine.getSSLParameters(), sslContext.getDefaultSSLParameters());
+ assertCipherSuitesEqual(sslEngine.getEnabledCipherSuites(),
+ sslContext.getDefaultSSLParameters().getCipherSuites());
+ assertProtocolsEqual(sslEngine.getEnabledProtocols(),
+ sslContext.getDefaultSSLParameters().getProtocols());
+
+ assertCipherSuitesEqual(sslEngine.getSupportedCipherSuites(),
+ sslContext.getSupportedSSLParameters().getCipherSuites());
+ assertProtocolsEqual(sslEngine.getSupportedProtocols(),
+ sslContext.getSupportedSSLParameters().getProtocols());
+ }
+
+ private static void assertSSLParametersEqual(SSLParameters expected, SSLParameters actual) {
+ assertCipherSuitesEqual(expected.getCipherSuites(), actual.getCipherSuites());
+ assertProtocolsEqual(expected.getProtocols(), actual.getProtocols());
+ assertEquals(expected.getNeedClientAuth(), actual.getNeedClientAuth());
+ assertEquals(expected.getWantClientAuth(), actual.getWantClientAuth());
+ }
+
+ private static void assertCipherSuitesEqual(String[] expected, String[] actual) {
+ assertEquals(Arrays.asList(expected), Arrays.asList(actual));
+ }
+
+ private static void assertProtocolsEqual(String[] expected, String[] actual) {
+ // IMPLEMENTATION NOTE: The order of protocols versions does not matter. Similarly, it only
+ // matters whether a protocol version is present or absent in the array. These arrays are
+ // supposed to represent sets of protocol versions. Thus, we treat them as such.
+ assertEquals(new HashSet<String>(Arrays.asList(expected)),
+ new HashSet<String>(Arrays.asList(actual)));
+ }
+
+ /**
+ * Asserts that the {@code container} contains all the {@code elements}.
+ */
+ private static void assertContainsAll(String message, String[] container, String[] elements) {
+ Set<String> elementsNotInContainer = new HashSet<String>(Arrays.asList(elements));
+ elementsNotInContainer.removeAll(Arrays.asList(container));
+ assertEquals(message, Collections.EMPTY_SET, elementsNotInContainer);
+ }
+}
diff --git a/support/src/test/java/libcore/javax/net/ssl/SSLDefaultConfigurationAsserts.java b/support/src/test/java/libcore/javax/net/ssl/SSLDefaultConfigurationAsserts.java
deleted file mode 100644
index d54f5e5..0000000
--- a/support/src/test/java/libcore/javax/net/ssl/SSLDefaultConfigurationAsserts.java
+++ /dev/null
@@ -1,202 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package libcore.javax.net.ssl;
-
-import java.io.IOException;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.Set;
-import javax.net.ssl.SSLContext;
-import javax.net.ssl.SSLEngine;
-import javax.net.ssl.SSLParameters;
-import javax.net.ssl.SSLServerSocket;
-import javax.net.ssl.SSLServerSocketFactory;
-import javax.net.ssl.SSLSocket;
-import javax.net.ssl.SSLSocketFactory;
-import junit.framework.Assert;
-import libcore.java.security.StandardNames;
-
-/**
- * Assertions about the default configuration of TLS/SSL primitives.
- */
-public abstract class SSLDefaultConfigurationAsserts extends Assert {
-
- /** Hidden constructor to prevent instantiation. */
- private SSLDefaultConfigurationAsserts() {}
-
- /**
- * Asserts that the provided {@link SSLContext} has the expected default configuration.
- */
- public static void assertSSLContext(SSLContext sslContext) throws IOException {
- assertDefaultSSLParametersClient(sslContext.getDefaultSSLParameters());
- assertSupportedSSLParametersClient(sslContext.getSupportedSSLParameters());
- assertSSLSocketFactory(sslContext.getSocketFactory());
- assertSSLServerSocketFactory(sslContext.getServerSocketFactory());
- assertSSLEngine(sslContext.createSSLEngine());
- assertSSLEngine(sslContext.createSSLEngine(null, -1));
- }
-
- /**
- * Asserts that the provided {@link SSLSocketFactory} has the expected default configuration.
- */
- public static void assertSSLSocketFactory(SSLSocketFactory sslSocketFactory) throws IOException {
- StandardNames.assertDefaultCipherSuites(sslSocketFactory.getDefaultCipherSuites());
- StandardNames.assertSupportedCipherSuites(sslSocketFactory.getSupportedCipherSuites());
- assertContainsAll("Unsupported default cipher suites",
- sslSocketFactory.getSupportedCipherSuites(),
- sslSocketFactory.getDefaultCipherSuites());
-
- assertSSLSocket((SSLSocket) sslSocketFactory.createSocket());
- }
-
- /**
- * Asserts that the provided {@link SSLServerSocketFactory} has the expected default
- * configuration.
- */
- public static void assertSSLServerSocketFactory(SSLServerSocketFactory sslServerSocketFactory)
- throws IOException {
- StandardNames.assertDefaultCipherSuites(sslServerSocketFactory.getDefaultCipherSuites());
- StandardNames.assertSupportedCipherSuites(sslServerSocketFactory.getSupportedCipherSuites());
- assertContainsAll("Unsupported default cipher suites",
- sslServerSocketFactory.getSupportedCipherSuites(),
- sslServerSocketFactory.getDefaultCipherSuites());
-
- assertSSLServerSocket((SSLServerSocket) sslServerSocketFactory.createServerSocket());
- }
-
- /**
- * Asserts that the provided {@link SSLSocket} has the expected default configuration.
- */
- public static void assertSSLSocket(SSLSocket sslSocket) {
- assertSSLParametersClient(sslSocket.getSSLParameters());
-
- StandardNames.assertDefaultCipherSuites(sslSocket.getEnabledCipherSuites());
- StandardNames.assertSupportedCipherSuites(sslSocket.getSupportedCipherSuites());
- assertContainsAll("Unsupported enabled cipher suites",
- sslSocket.getSupportedCipherSuites(),
- sslSocket.getEnabledCipherSuites());
-
- StandardNames.assertDefaultProtocolsClient(sslSocket.getEnabledProtocols());
- StandardNames.assertSupportedProtocols(sslSocket.getSupportedProtocols());
- assertContainsAll("Unsupported enabled protocols",
- sslSocket.getSupportedProtocols(),
- sslSocket.getEnabledProtocols());
-
- assertTrue(sslSocket.getUseClientMode());
- assertTrue(sslSocket.getEnableSessionCreation());
- assertFalse(sslSocket.getNeedClientAuth());
- assertFalse(sslSocket.getWantClientAuth());
- }
-
- /**
- * Asserts that the provided {@link SSLServerSocket} has the expected default configuration.
- */
- public static void assertSSLServerSocket(SSLServerSocket sslServerSocket) {
- // TODO: Check SSLParameters when supported by SSLServerSocket API
-
- StandardNames.assertDefaultCipherSuites(sslServerSocket.getEnabledCipherSuites());
- StandardNames.assertSupportedCipherSuites(sslServerSocket.getSupportedCipherSuites());
- assertContainsAll("Unsupported enabled cipher suites",
- sslServerSocket.getSupportedCipherSuites(),
- sslServerSocket.getEnabledCipherSuites());
-
- StandardNames.assertDefaultProtocolsServer(sslServerSocket.getEnabledProtocols());
- StandardNames.assertSupportedProtocols(sslServerSocket.getSupportedProtocols());
- assertContainsAll("Unsupported enabled protocols",
- sslServerSocket.getSupportedProtocols(),
- sslServerSocket.getEnabledProtocols());
-
- assertTrue(sslServerSocket.getEnableSessionCreation());
- assertFalse(sslServerSocket.getNeedClientAuth());
- assertFalse(sslServerSocket.getWantClientAuth());
- }
-
- /**
- * Asserts that the provided {@link SSLEngine} has the expected default configuration.
- */
- public static void assertSSLEngine(SSLEngine sslEngine) {
- assertFalse(sslEngine.getUseClientMode());
- assertSSLEngineSSLParameters(sslEngine.getSSLParameters());
-
- StandardNames.assertDefaultCipherSuites(sslEngine.getEnabledCipherSuites());
- StandardNames.assertSupportedCipherSuites(sslEngine.getSupportedCipherSuites());
- assertContainsAll("Unsupported enabled cipher suites",
- sslEngine.getSupportedCipherSuites(),
- sslEngine.getEnabledCipherSuites());
-
- StandardNames.assertSSLEngineDefaultProtocols(sslEngine.getEnabledProtocols());
- StandardNames.assertSupportedProtocols(sslEngine.getSupportedProtocols());
- assertContainsAll("Unsupported enabled protocols",
- sslEngine.getSupportedProtocols(),
- sslEngine.getEnabledProtocols());
-
- assertTrue(sslEngine.getEnableSessionCreation());
- assertFalse(sslEngine.getNeedClientAuth());
- assertFalse(sslEngine.getWantClientAuth());
- }
-
- /**
- * Asserts that the provided {@link SSLParameters} describe the expected default configuration
- * for client-side mode of operation.
- */
- public static void assertSSLParametersClient(SSLParameters sslParameters) {
- assertDefaultSSLParametersClient(sslParameters);
- }
-
- /**
- * Asserts that the provided default {@link SSLParameters} are as expected for client-side mode of
- * operation.
- */
- private static void assertDefaultSSLParametersClient(SSLParameters sslParameters) {
- StandardNames.assertDefaultCipherSuites(sslParameters.getCipherSuites());
- StandardNames.assertDefaultProtocolsClient(sslParameters.getProtocols());
- assertFalse(sslParameters.getWantClientAuth());
- assertFalse(sslParameters.getNeedClientAuth());
- }
-
- /**
- * Asserts that the provided supported {@link SSLParameters} are as expected for client-side mode
- * of operation.
- */
- private static void assertSupportedSSLParametersClient(SSLParameters sslParameters) {
- StandardNames.assertSupportedCipherSuites(sslParameters.getCipherSuites());
- StandardNames.assertSupportedProtocols(sslParameters.getProtocols());
- assertFalse(sslParameters.getWantClientAuth());
- assertFalse(sslParameters.getNeedClientAuth());
- }
-
- /**
- * Asserts that the provided {@link SSLParameters} has the expected default configuration for
- * {@link SSLEngine}.
- */
- public static void assertSSLEngineSSLParameters(SSLParameters sslParameters) {
- StandardNames.assertDefaultCipherSuites(sslParameters.getCipherSuites());
- StandardNames.assertSSLEngineDefaultProtocols(sslParameters.getProtocols());
- assertFalse(sslParameters.getWantClientAuth());
- assertFalse(sslParameters.getNeedClientAuth());
- }
-
- /**
- * Asserts that the {@code container} contains all the {@code elements}.
- */
- private static void assertContainsAll(String message, String[] container, String[] elements) {
- Set<String> elementsNotInContainer = new HashSet<String>(Arrays.asList(elements));
- elementsNotInContainer.removeAll(Arrays.asList(container));
- assertEquals(message, Collections.EMPTY_SET, elementsNotInContainer);
- }
-}
diff --git a/support/src/test/java/libcore/javax/net/ssl/TestSSLEnginePair.java b/support/src/test/java/libcore/javax/net/ssl/TestSSLEnginePair.java
index 6c2c943..3a12629 100644
--- a/support/src/test/java/libcore/javax/net/ssl/TestSSLEnginePair.java
+++ b/support/src/test/java/libcore/javax/net/ssl/TestSSLEnginePair.java
@@ -21,6 +21,7 @@ import java.nio.ByteBuffer;
import javax.net.ssl.SSLEngine;
import javax.net.ssl.SSLEngineResult;
import javax.net.ssl.SSLEngineResult.HandshakeStatus;
+import javax.net.ssl.SSLException;
import javax.net.ssl.SSLSession;
import junit.framework.Assert;
@@ -134,6 +135,23 @@ public final class TestSSLEnginePair extends Assert {
void beforeBeginHandshake(SSLEngine client, SSLEngine server) {}
}
+ public void close() throws SSLException {
+ close(new SSLEngine[] { client, server });
+ }
+
+ public static void close(SSLEngine[] engines) {
+ try {
+ for (SSLEngine engine : engines) {
+ if (engine != null) {
+ engine.closeInbound();
+ engine.closeOutbound();
+ }
+ }
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+
private static boolean handshakeCompleted(SSLEngine engine,
ByteBuffer output,
ByteBuffer input,
diff --git a/support/src/test/java/libcore/tlswire/handshake/CipherSuite.java b/support/src/test/java/libcore/tlswire/handshake/CipherSuite.java
new file mode 100644
index 0000000..88ce2f2
--- /dev/null
+++ b/support/src/test/java/libcore/tlswire/handshake/CipherSuite.java
@@ -0,0 +1,464 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package libcore.tlswire.handshake;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * {@code CipherSuite} enum from TLS 1.2 RFC 5246.
+ */
+public class CipherSuite {
+ // The list of cipher suites below is based on IANA registry
+ // https://www.iana.org/assignments/tls-parameters/tls-parameters.xhtml
+ private static final CipherSuite[] CIPHER_SUITES = new CipherSuite[] {
+ new CipherSuite(0x0000, "TLS_NULL_WITH_NULL_NULL"),
+ new CipherSuite(0x0001, "TLS_RSA_WITH_NULL_MD5", "SSL_RSA_WITH_NULL_MD5"),
+ new CipherSuite(0x0002, "TLS_RSA_WITH_NULL_SHA", "SSL_RSA_WITH_NULL_SHA"),
+ new CipherSuite(0x0003, "TLS_RSA_EXPORT_WITH_RC4_40_MD5", "SSL_RSA_EXPORT_WITH_RC4_40_MD5"),
+ new CipherSuite(0x0004, "TLS_RSA_WITH_RC4_128_MD5", "SSL_RSA_WITH_RC4_128_MD5"),
+ new CipherSuite(0x0005, "TLS_RSA_WITH_RC4_128_SHA", "SSL_RSA_WITH_RC4_128_SHA"),
+ new CipherSuite(0x0006, "TLS_RSA_EXPORT_WITH_RC2_CBC_40_MD5"),
+ new CipherSuite(0x0007, "TLS_RSA_WITH_IDEA_CBC_SHA"),
+ new CipherSuite(0x0008, "TLS_RSA_EXPORT_WITH_DES40_CBC_SHA",
+ "SSL_RSA_EXPORT_WITH_DES40_CBC_SHA"),
+ new CipherSuite(0x0009, "TLS_RSA_WITH_DES_CBC_SHA", "SSL_RSA_WITH_DES_CBC_SHA"),
+ new CipherSuite(0x000a, "TLS_RSA_WITH_3DES_EDE_CBC_SHA", "SSL_RSA_WITH_3DES_EDE_CBC_SHA"),
+ new CipherSuite(0x000b, "TLS_DH_DSS_EXPORT_WITH_DES40_CBC_SHA"),
+ new CipherSuite(0x000c, "TLS_DH_DSS_WITH_DES_CBC_SHA"),
+ new CipherSuite(0x000d, "TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA"),
+ new CipherSuite(0x000e, "TLS_DH_RSA_EXPORT_WITH_DES40_CBC_SHA"),
+ new CipherSuite(0x000f, "TLS_DH_RSA_WITH_DES_CBC_SHA"),
+ new CipherSuite(0x0010, "TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA"),
+ new CipherSuite(0x0011, "TLS_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA",
+ "SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA"),
+ new CipherSuite(0x0012, "TLS_DHE_DSS_WITH_DES_CBC_SHA", "SSL_DHE_DSS_WITH_DES_CBC_SHA"),
+ new CipherSuite(0x0013, "TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA",
+ "SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA"),
+ new CipherSuite(0x0014, "TLS_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA",
+ "SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA"),
+ new CipherSuite(0x0015, "TLS_DHE_RSA_WITH_DES_CBC_SHA", "SSL_DHE_RSA_WITH_DES_CBC_SHA"),
+ new CipherSuite(0x0016, "TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA",
+ "SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA"),
+ new CipherSuite(0x0017, "TLS_DH_anon_EXPORT_WITH_RC4_40_MD5",
+ "SSL_DH_anon_EXPORT_WITH_RC4_40_MD5"),
+ new CipherSuite(0x0018, "TLS_DH_anon_WITH_RC4_128_MD5", "SSL_DH_anon_WITH_RC4_128_MD5"),
+ new CipherSuite(0x0019, "TLS_DH_anon_EXPORT_WITH_DES40_CBC_SHA",
+ "SSL_DH_anon_EXPORT_WITH_DES40_CBC_SHA"),
+ new CipherSuite(0x001a, "TLS_DH_anon_WITH_DES_CBC_SHA", "SSL_DH_anon_WITH_DES_CBC_SHA"),
+ new CipherSuite(0x001b, "TLS_DH_anon_WITH_3DES_EDE_CBC_SHA",
+ "SSL_DH_anon_WITH_3DES_EDE_CBC_SHA"),
+ new CipherSuite(0x001e, "TLS_KRB5_WITH_DES_CBC_SHA"),
+ new CipherSuite(0x001f, "TLS_KRB5_WITH_3DES_EDE_CBC_SHA"),
+ new CipherSuite(0x0020, "TLS_KRB5_WITH_RC4_128_SHA"),
+ new CipherSuite(0x0021, "TLS_KRB5_WITH_IDEA_CBC_SHA"),
+ new CipherSuite(0x0022, "TLS_KRB5_WITH_DES_CBC_MD5"),
+ new CipherSuite(0x0023, "TLS_KRB5_WITH_3DES_EDE_CBC_MD5"),
+ new CipherSuite(0x0024, "TLS_KRB5_WITH_RC4_128_MD5"),
+ new CipherSuite(0x0025, "TLS_KRB5_WITH_IDEA_CBC_MD5"),
+ new CipherSuite(0x0026, "TLS_KRB5_EXPORT_WITH_DES_CBC_40_SHA"),
+ new CipherSuite(0x0027, "TLS_KRB5_EXPORT_WITH_RC2_CBC_40_SHA"),
+ new CipherSuite(0x0028, "TLS_KRB5_EXPORT_WITH_RC4_40_SHA"),
+ new CipherSuite(0x0029, "TLS_KRB5_EXPORT_WITH_DES_CBC_40_MD5"),
+ new CipherSuite(0x002a, "TLS_KRB5_EXPORT_WITH_RC2_CBC_40_MD5"),
+ new CipherSuite(0x002b, "TLS_KRB5_EXPORT_WITH_RC4_40_MD5"),
+ new CipherSuite(0x002c, "TLS_PSK_WITH_NULL_SHA"),
+ new CipherSuite(0x002d, "TLS_DHE_PSK_WITH_NULL_SHA"),
+ new CipherSuite(0x002e, "TLS_RSA_PSK_WITH_NULL_SHA"),
+ new CipherSuite(0x002f, "TLS_RSA_WITH_AES_128_CBC_SHA"),
+ new CipherSuite(0x0030, "TLS_DH_DSS_WITH_AES_128_CBC_SHA"),
+ new CipherSuite(0x0031, "TLS_DH_RSA_WITH_AES_128_CBC_SHA"),
+ new CipherSuite(0x0032, "TLS_DHE_DSS_WITH_AES_128_CBC_SHA"),
+ new CipherSuite(0x0033, "TLS_DHE_RSA_WITH_AES_128_CBC_SHA"),
+ new CipherSuite(0x0034, "TLS_DH_anon_WITH_AES_128_CBC_SHA"),
+ new CipherSuite(0x0035, "TLS_RSA_WITH_AES_256_CBC_SHA"),
+ new CipherSuite(0x0036, "TLS_DH_DSS_WITH_AES_256_CBC_SHA"),
+ new CipherSuite(0x0037, "TLS_DH_RSA_WITH_AES_256_CBC_SHA"),
+ new CipherSuite(0x0038, "TLS_DHE_DSS_WITH_AES_256_CBC_SHA"),
+ new CipherSuite(0x0039, "TLS_DHE_RSA_WITH_AES_256_CBC_SHA"),
+ new CipherSuite(0x003a, "TLS_DH_anon_WITH_AES_256_CBC_SHA"),
+ new CipherSuite(0x003b, "TLS_RSA_WITH_NULL_SHA256"),
+ new CipherSuite(0x003c, "TLS_RSA_WITH_AES_128_CBC_SHA256"),
+ new CipherSuite(0x003d, "TLS_RSA_WITH_AES_256_CBC_SHA256"),
+ new CipherSuite(0x003e, "TLS_DH_DSS_WITH_AES_128_CBC_SHA256"),
+ new CipherSuite(0x003f, "TLS_DH_RSA_WITH_AES_128_CBC_SHA256"),
+ new CipherSuite(0x0040, "TLS_DHE_DSS_WITH_AES_128_CBC_SHA256"),
+ new CipherSuite(0x0041, "TLS_RSA_WITH_CAMELLIA_128_CBC_SHA"),
+ new CipherSuite(0x0042, "TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA"),
+ new CipherSuite(0x0043, "TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA"),
+ new CipherSuite(0x0044, "TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA"),
+ new CipherSuite(0x0045, "TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA"),
+ new CipherSuite(0x0046, "TLS_DH_anon_WITH_CAMELLIA_128_CBC_SHA"),
+ new CipherSuite(0x0060, "TLS_RSA_EXPORT1024_WITH_RC4_56_MD5"),
+ new CipherSuite(0x0061, "TLS_RSA_EXPORT1024_WITH_RC2_CBC_56_MD5"),
+ new CipherSuite(0x0062, "TLS_RSA_EXPORT1024_WITH_DES_CBC_SHA"),
+ new CipherSuite(0x0063, "TLS_DHE_DSS_EXPORT1024_WITH_DES_CBC_SHA"),
+ new CipherSuite(0x0064, "TLS_RSA_EXPORT1024_WITH_RC4_56_SHA"),
+ new CipherSuite(0x0065, "TLS_DHE_DSS_EXPORT1024_WITH_RC4_56_SHA"),
+ new CipherSuite(0x0066, "TLS_DHE_DSS_WITH_RC4_128_SHA"),
+ new CipherSuite(0x0067, "TLS_DHE_RSA_WITH_AES_128_CBC_SHA256"),
+ new CipherSuite(0x0068, "TLS_DH_DSS_WITH_AES_256_CBC_SHA256"),
+ new CipherSuite(0x0069, "TLS_DH_RSA_WITH_AES_256_CBC_SHA256"),
+ new CipherSuite(0x006a, "TLS_DHE_DSS_WITH_AES_256_CBC_SHA256"),
+ new CipherSuite(0x006b, "TLS_DHE_RSA_WITH_AES_256_CBC_SHA256"),
+ new CipherSuite(0x006c, "TLS_DH_anon_WITH_AES_128_CBC_SHA256"),
+ new CipherSuite(0x006d, "TLS_DH_anon_WITH_AES_256_CBC_SHA256"),
+ new CipherSuite(0x0084, "TLS_RSA_WITH_CAMELLIA_256_CBC_SHA"),
+ new CipherSuite(0x0085, "TLS_DH_DSS_WITH_CAMELLIA_256_CBC_SHA"),
+ new CipherSuite(0x0086, "TLS_DH_RSA_WITH_CAMELLIA_256_CBC_SHA"),
+ new CipherSuite(0x0087, "TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA"),
+ new CipherSuite(0x0088, "TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA"),
+ new CipherSuite(0x0089, "TLS_DH_anon_WITH_CAMELLIA_256_CBC_SHA"),
+ new CipherSuite(0x008a, "TLS_PSK_WITH_RC4_128_SHA"),
+ new CipherSuite(0x008b, "TLS_PSK_WITH_3DES_EDE_CBC_SHA"),
+ new CipherSuite(0x008c, "TLS_PSK_WITH_AES_128_CBC_SHA"),
+ new CipherSuite(0x008d, "TLS_PSK_WITH_AES_256_CBC_SHA"),
+ new CipherSuite(0x008e, "TLS_DHE_PSK_WITH_RC4_128_SHA"),
+ new CipherSuite(0x008f, "TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA"),
+ new CipherSuite(0x0090, "TLS_DHE_PSK_WITH_AES_128_CBC_SHA"),
+ new CipherSuite(0x0091, "TLS_DHE_PSK_WITH_AES_256_CBC_SHA"),
+ new CipherSuite(0x0092, "TLS_RSA_PSK_WITH_RC4_128_SHA"),
+ new CipherSuite(0x0093, "TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA"),
+ new CipherSuite(0x0094, "TLS_RSA_PSK_WITH_AES_128_CBC_SHA"),
+ new CipherSuite(0x0095, "TLS_RSA_PSK_WITH_AES_256_CBC_SHA"),
+ new CipherSuite(0x0096, "TLS_RSA_WITH_SEED_CBC_SHA"),
+ new CipherSuite(0x0097, "TLS_DH_DSS_WITH_SEED_CBC_SHA"),
+ new CipherSuite(0x0098, "TLS_DH_RSA_WITH_SEED_CBC_SHA"),
+ new CipherSuite(0x0099, "TLS_DHE_DSS_WITH_SEED_CBC_SHA"),
+ new CipherSuite(0x009a, "TLS_DHE_RSA_WITH_SEED_CBC_SHA"),
+ new CipherSuite(0x009b, "TLS_DH_anon_WITH_SEED_CBC_SHA"),
+ new CipherSuite(0x009c, "TLS_RSA_WITH_AES_128_GCM_SHA256"),
+ new CipherSuite(0x009d, "TLS_RSA_WITH_AES_256_GCM_SHA384"),
+ new CipherSuite(0x009e, "TLS_DHE_RSA_WITH_AES_128_GCM_SHA256"),
+ new CipherSuite(0x009f, "TLS_DHE_RSA_WITH_AES_256_GCM_SHA384"),
+ new CipherSuite(0x00a0, "TLS_DH_RSA_WITH_AES_128_GCM_SHA256"),
+ new CipherSuite(0x00a1, "TLS_DH_RSA_WITH_AES_256_GCM_SHA384"),
+ new CipherSuite(0x00a2, "TLS_DHE_DSS_WITH_AES_128_GCM_SHA256"),
+ new CipherSuite(0x00a3, "TLS_DHE_DSS_WITH_AES_256_GCM_SHA384"),
+ new CipherSuite(0x00a4, "TLS_DH_DSS_WITH_AES_128_GCM_SHA256"),
+ new CipherSuite(0x00a5, "TLS_DH_DSS_WITH_AES_256_GCM_SHA384"),
+ new CipherSuite(0x00a6, "TLS_DH_anon_WITH_AES_128_GCM_SHA256"),
+ new CipherSuite(0x00a7, "TLS_DH_anon_WITH_AES_256_GCM_SHA384"),
+ new CipherSuite(0x00a8, "TLS_PSK_WITH_AES_128_GCM_SHA256"),
+ new CipherSuite(0x00a9, "TLS_PSK_WITH_AES_256_GCM_SHA384"),
+ new CipherSuite(0x00aa, "TLS_DHE_PSK_WITH_AES_128_GCM_SHA256"),
+ new CipherSuite(0x00ab, "TLS_DHE_PSK_WITH_AES_256_GCM_SHA384"),
+ new CipherSuite(0x00ac, "TLS_RSA_PSK_WITH_AES_128_GCM_SHA256"),
+ new CipherSuite(0x00ad, "TLS_RSA_PSK_WITH_AES_256_GCM_SHA384"),
+ new CipherSuite(0x00ae, "TLS_PSK_WITH_AES_128_CBC_SHA256"),
+ new CipherSuite(0x00af, "TLS_PSK_WITH_AES_256_CBC_SHA384"),
+ new CipherSuite(0x00b0, "TLS_PSK_WITH_NULL_SHA256"),
+ new CipherSuite(0x00b1, "TLS_PSK_WITH_NULL_SHA384"),
+ new CipherSuite(0x00b2, "TLS_DHE_PSK_WITH_AES_128_CBC_SHA256"),
+ new CipherSuite(0x00b3, "TLS_DHE_PSK_WITH_AES_256_CBC_SHA384"),
+ new CipherSuite(0x00b4, "TLS_DHE_PSK_WITH_NULL_SHA256"),
+ new CipherSuite(0x00b5, "TLS_DHE_PSK_WITH_NULL_SHA384"),
+ new CipherSuite(0x00b6, "TLS_RSA_PSK_WITH_AES_128_CBC_SHA256"),
+ new CipherSuite(0x00b7, "TLS_RSA_PSK_WITH_AES_256_CBC_SHA384"),
+ new CipherSuite(0x00b8, "TLS_RSA_PSK_WITH_NULL_SHA256"),
+ new CipherSuite(0x00b9, "TLS_RSA_PSK_WITH_NULL_SHA384"),
+ new CipherSuite(0x00ba, "TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256"),
+ new CipherSuite(0x00bb, "TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA256"),
+ new CipherSuite(0x00bc, "TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA256"),
+ new CipherSuite(0x00bd, "TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA256"),
+ new CipherSuite(0x00be, "TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256"),
+ new CipherSuite(0x00bf, "TLS_DH_anon_WITH_CAMELLIA_128_CBC_SHA256"),
+ new CipherSuite(0x00c0, "TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256"),
+ new CipherSuite(0x00c1, "TLS_DH_DSS_WITH_CAMELLIA_256_CBC_SHA256"),
+ new CipherSuite(0x00c2, "TLS_DH_RSA_WITH_CAMELLIA_256_CBC_SHA256"),
+ new CipherSuite(0x00c3, "TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA256"),
+ new CipherSuite(0x00c4, "TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256"),
+ new CipherSuite(0x00c5, "TLS_DH_anon_WITH_CAMELLIA_256_CBC_SHA256"),
+ new CipherSuite(0x00ff, "TLS_EMPTY_RENEGOTIATION_INFO_SCSV"),
+ new CipherSuite(0x5600, "TLS_FALLBACK_SCSV"),
+ new CipherSuite(0xc001, "TLS_ECDH_ECDSA_WITH_NULL_SHA"),
+ new CipherSuite(0xc002, "TLS_ECDH_ECDSA_WITH_RC4_128_SHA"),
+ new CipherSuite(0xc003, "TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA"),
+ new CipherSuite(0xc004, "TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA"),
+ new CipherSuite(0xc005, "TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA"),
+ new CipherSuite(0xc006, "TLS_ECDHE_ECDSA_WITH_NULL_SHA"),
+ new CipherSuite(0xc007, "TLS_ECDHE_ECDSA_WITH_RC4_128_SHA"),
+ new CipherSuite(0xc008, "TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA"),
+ new CipherSuite(0xc009, "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA"),
+ new CipherSuite(0xc00a, "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA"),
+ new CipherSuite(0xc00b, "TLS_ECDH_RSA_WITH_NULL_SHA"),
+ new CipherSuite(0xc00c, "TLS_ECDH_RSA_WITH_RC4_128_SHA"),
+ new CipherSuite(0xc00d, "TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA"),
+ new CipherSuite(0xc00e, "TLS_ECDH_RSA_WITH_AES_128_CBC_SHA"),
+ new CipherSuite(0xc00f, "TLS_ECDH_RSA_WITH_AES_256_CBC_SHA"),
+ new CipherSuite(0xc010, "TLS_ECDHE_RSA_WITH_NULL_SHA"),
+ new CipherSuite(0xc011, "TLS_ECDHE_RSA_WITH_RC4_128_SHA"),
+ new CipherSuite(0xc012, "TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA"),
+ new CipherSuite(0xc013, "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA"),
+ new CipherSuite(0xc014, "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA"),
+ new CipherSuite(0xc015, "TLS_ECDH_anon_WITH_NULL_SHA"),
+ new CipherSuite(0xc016, "TLS_ECDH_anon_WITH_RC4_128_SHA"),
+ new CipherSuite(0xc017, "TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA"),
+ new CipherSuite(0xc018, "TLS_ECDH_anon_WITH_AES_128_CBC_SHA"),
+ new CipherSuite(0xc019, "TLS_ECDH_anon_WITH_AES_256_CBC_SHA"),
+ new CipherSuite(0xc01a, "TLS_SRP_SHA_WITH_3DES_EDE_CBC_SHA"),
+ new CipherSuite(0xc01b, "TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA"),
+ new CipherSuite(0xc01c, "TLS_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA"),
+ new CipherSuite(0xc01d, "TLS_SRP_SHA_WITH_AES_128_CBC_SHA"),
+ new CipherSuite(0xc01e, "TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA"),
+ new CipherSuite(0xc01f, "TLS_SRP_SHA_DSS_WITH_AES_128_CBC_SHA"),
+ new CipherSuite(0xc020, "TLS_SRP_SHA_WITH_AES_256_CBC_SHA"),
+ new CipherSuite(0xc021, "TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA"),
+ new CipherSuite(0xc022, "TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA"),
+ new CipherSuite(0xc023, "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256"),
+ new CipherSuite(0xc024, "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384"),
+ new CipherSuite(0xc025, "TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256"),
+ new CipherSuite(0xc026, "TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384"),
+ new CipherSuite(0xc027, "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256"),
+ new CipherSuite(0xc028, "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384"),
+ new CipherSuite(0xc029, "TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256"),
+ new CipherSuite(0xc02a, "TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384"),
+ new CipherSuite(0xc02b, "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256"),
+ new CipherSuite(0xc02c, "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384"),
+ new CipherSuite(0xc02d, "TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256"),
+ new CipherSuite(0xc02e, "TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384"),
+ new CipherSuite(0xc02f, "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256"),
+ new CipherSuite(0xc030, "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384"),
+ new CipherSuite(0xc031, "TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256"),
+ new CipherSuite(0xc032, "TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384"),
+ new CipherSuite(0xc033, "TLS_ECDHE_PSK_WITH_RC4_128_SHA"),
+ new CipherSuite(0xc034, "TLS_ECDHE_PSK_WITH_3DES_EDE_CBC_SHA"),
+ new CipherSuite(0xc035, "TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA"),
+ new CipherSuite(0xc036, "TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA"),
+ new CipherSuite(0xc037, "TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256"),
+ new CipherSuite(0xc038, "TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA384"),
+ new CipherSuite(0xc039, "TLS_ECDHE_PSK_WITH_NULL_SHA"),
+ new CipherSuite(0xc03a, "TLS_ECDHE_PSK_WITH_NULL_SHA256"),
+ new CipherSuite(0xc03b, "TLS_ECDHE_PSK_WITH_NULL_SHA384"),
+ new CipherSuite(0xc03c, "TLS_RSA_WITH_ARIA_128_CBC_SHA256"),
+ new CipherSuite(0xc03d, "TLS_RSA_WITH_ARIA_256_CBC_SHA384"),
+ new CipherSuite(0xc03e, "TLS_DH_DSS_WITH_ARIA_128_CBC_SHA256"),
+ new CipherSuite(0xc03f, "TLS_DH_DSS_WITH_ARIA_256_CBC_SHA384"),
+ new CipherSuite(0xc040, "TLS_DH_RSA_WITH_ARIA_128_CBC_SHA256"),
+ new CipherSuite(0xc041, "TLS_DH_RSA_WITH_ARIA_256_CBC_SHA384"),
+ new CipherSuite(0xc042, "TLS_DHE_DSS_WITH_ARIA_128_CBC_SHA256"),
+ new CipherSuite(0xc043, "TLS_DHE_DSS_WITH_ARIA_256_CBC_SHA384"),
+ new CipherSuite(0xc044, "TLS_DHE_RSA_WITH_ARIA_128_CBC_SHA256"),
+ new CipherSuite(0xc045, "TLS_DHE_RSA_WITH_ARIA_256_CBC_SHA384"),
+ new CipherSuite(0xc046, "TLS_DH_anon_WITH_ARIA_128_CBC_SHA256"),
+ new CipherSuite(0xc047, "TLS_DH_anon_WITH_ARIA_256_CBC_SHA384"),
+ new CipherSuite(0xc048, "TLS_ECDHE_ECDSA_WITH_ARIA_128_CBC_SHA256"),
+ new CipherSuite(0xc049, "TLS_ECDHE_ECDSA_WITH_ARIA_256_CBC_SHA384"),
+ new CipherSuite(0xc04a, "TLS_ECDH_ECDSA_WITH_ARIA_128_CBC_SHA256"),
+ new CipherSuite(0xc04b, "TLS_ECDH_ECDSA_WITH_ARIA_256_CBC_SHA384"),
+ new CipherSuite(0xc04c, "TLS_ECDHE_RSA_WITH_ARIA_128_CBC_SHA256"),
+ new CipherSuite(0xc04d, "TLS_ECDHE_RSA_WITH_ARIA_256_CBC_SHA384"),
+ new CipherSuite(0xc04e, "TLS_ECDH_RSA_WITH_ARIA_128_CBC_SHA256"),
+ new CipherSuite(0xc04f, "TLS_ECDH_RSA_WITH_ARIA_256_CBC_SHA384"),
+ new CipherSuite(0xc050, "TLS_RSA_WITH_ARIA_128_GCM_SHA256"),
+ new CipherSuite(0xc051, "TLS_RSA_WITH_ARIA_256_GCM_SHA384"),
+ new CipherSuite(0xc052, "TLS_DHE_RSA_WITH_ARIA_128_GCM_SHA256"),
+ new CipherSuite(0xc053, "TLS_DHE_RSA_WITH_ARIA_256_GCM_SHA384"),
+ new CipherSuite(0xc054, "TLS_DH_RSA_WITH_ARIA_128_GCM_SHA256"),
+ new CipherSuite(0xc055, "TLS_DH_RSA_WITH_ARIA_256_GCM_SHA384"),
+ new CipherSuite(0xc056, "TLS_DHE_DSS_WITH_ARIA_128_GCM_SHA256"),
+ new CipherSuite(0xc057, "TLS_DHE_DSS_WITH_ARIA_256_GCM_SHA384"),
+ new CipherSuite(0xc058, "TLS_DH_DSS_WITH_ARIA_128_GCM_SHA256"),
+ new CipherSuite(0xc059, "TLS_DH_DSS_WITH_ARIA_256_GCM_SHA384"),
+ new CipherSuite(0xc05a, "TLS_DH_anon_WITH_ARIA_128_GCM_SHA256"),
+ new CipherSuite(0xc05b, "TLS_DH_anon_WITH_ARIA_256_GCM_SHA384"),
+ new CipherSuite(0xc05c, "TLS_ECDHE_ECDSA_WITH_ARIA_128_GCM_SHA256"),
+ new CipherSuite(0xc05d, "TLS_ECDHE_ECDSA_WITH_ARIA_256_GCM_SHA384"),
+ new CipherSuite(0xc05e, "TLS_ECDH_ECDSA_WITH_ARIA_128_GCM_SHA256"),
+ new CipherSuite(0xc05f, "TLS_ECDH_ECDSA_WITH_ARIA_256_GCM_SHA384"),
+ new CipherSuite(0xc060, "TLS_ECDHE_RSA_WITH_ARIA_128_GCM_SHA256"),
+ new CipherSuite(0xc061, "TLS_ECDHE_RSA_WITH_ARIA_256_GCM_SHA384"),
+ new CipherSuite(0xc062, "TLS_ECDH_RSA_WITH_ARIA_128_GCM_SHA256"),
+ new CipherSuite(0xc063, "TLS_ECDH_RSA_WITH_ARIA_256_GCM_SHA384"),
+ new CipherSuite(0xc064, "TLS_PSK_WITH_ARIA_128_CBC_SHA256"),
+ new CipherSuite(0xc065, "TLS_PSK_WITH_ARIA_256_CBC_SHA384"),
+ new CipherSuite(0xc066, "TLS_DHE_PSK_WITH_ARIA_128_CBC_SHA256"),
+ new CipherSuite(0xc067, "TLS_DHE_PSK_WITH_ARIA_256_CBC_SHA384"),
+ new CipherSuite(0xc068, "TLS_RSA_PSK_WITH_ARIA_128_CBC_SHA256"),
+ new CipherSuite(0xc069, "TLS_RSA_PSK_WITH_ARIA_256_CBC_SHA384"),
+ new CipherSuite(0xc06a, "TLS_PSK_WITH_ARIA_128_GCM_SHA256"),
+ new CipherSuite(0xc06b, "TLS_PSK_WITH_ARIA_256_GCM_SHA384"),
+ new CipherSuite(0xc06c, "TLS_DHE_PSK_WITH_ARIA_128_GCM_SHA256"),
+ new CipherSuite(0xc06d, "TLS_DHE_PSK_WITH_ARIA_256_GCM_SHA384"),
+ new CipherSuite(0xc06e, "TLS_RSA_PSK_WITH_ARIA_128_GCM_SHA256"),
+ new CipherSuite(0xc06f, "TLS_RSA_PSK_WITH_ARIA_256_GCM_SHA384"),
+ new CipherSuite(0xc070, "TLS_ECDHE_PSK_WITH_ARIA_128_CBC_SHA256"),
+ new CipherSuite(0xc071, "TLS_ECDHE_PSK_WITH_ARIA_256_CBC_SHA384"),
+ new CipherSuite(0xc072, "TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_CBC_SHA256"),
+ new CipherSuite(0xc073, "TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_CBC_SHA384"),
+ new CipherSuite(0xc074, "TLS_ECDH_ECDSA_WITH_CAMELLIA_128_CBC_SHA256"),
+ new CipherSuite(0xc075, "TLS_ECDH_ECDSA_WITH_CAMELLIA_256_CBC_SHA384"),
+ new CipherSuite(0xc076, "TLS_ECDHE_RSA_WITH_CAMELLIA_128_CBC_SHA256"),
+ new CipherSuite(0xc077, "TLS_ECDHE_RSA_WITH_CAMELLIA_256_CBC_SHA384"),
+ new CipherSuite(0xc078, "TLS_ECDH_RSA_WITH_CAMELLIA_128_CBC_SHA256"),
+ new CipherSuite(0xc079, "TLS_ECDH_RSA_WITH_CAMELLIA_256_CBC_SHA384"),
+ new CipherSuite(0xc07a, "TLS_RSA_WITH_CAMELLIA_128_GCM_SHA256"),
+ new CipherSuite(0xc07b, "TLS_RSA_WITH_CAMELLIA_256_GCM_SHA384"),
+ new CipherSuite(0xc07c, "TLS_DHE_RSA_WITH_CAMELLIA_128_GCM_SHA256"),
+ new CipherSuite(0xc07d, "TLS_DHE_RSA_WITH_CAMELLIA_256_GCM_SHA384"),
+ new CipherSuite(0xc07e, "TLS_DH_RSA_WITH_CAMELLIA_128_GCM_SHA256"),
+ new CipherSuite(0xc07f, "TLS_DH_RSA_WITH_CAMELLIA_256_GCM_SHA384"),
+ new CipherSuite(0xc080, "TLS_DHE_DSS_WITH_CAMELLIA_128_GCM_SHA256"),
+ new CipherSuite(0xc081, "TLS_DHE_DSS_WITH_CAMELLIA_256_GCM_SHA384"),
+ new CipherSuite(0xc082, "TLS_DH_DSS_WITH_CAMELLIA_128_GCM_SHA256"),
+ new CipherSuite(0xc083, "TLS_DH_DSS_WITH_CAMELLIA_256_GCM_SHA384"),
+ new CipherSuite(0xc084, "TLS_DH_anon_WITH_CAMELLIA_128_GCM_SHA256"),
+ new CipherSuite(0xc085, "TLS_DH_anon_WITH_CAMELLIA_256_GCM_SHA384"),
+ new CipherSuite(0xc086, "TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_GCM_SHA256"),
+ new CipherSuite(0xc087, "TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_GCM_SHA384"),
+ new CipherSuite(0xc088, "TLS_ECDH_ECDSA_WITH_CAMELLIA_128_GCM_SHA256"),
+ new CipherSuite(0xc089, "TLS_ECDH_ECDSA_WITH_CAMELLIA_256_GCM_SHA384"),
+ new CipherSuite(0xc08a, "TLS_ECDHE_RSA_WITH_CAMELLIA_128_GCM_SHA256"),
+ new CipherSuite(0xc08b, "TLS_ECDHE_RSA_WITH_CAMELLIA_256_GCM_SHA384"),
+ new CipherSuite(0xc08c, "TLS_ECDH_RSA_WITH_CAMELLIA_128_GCM_SHA256"),
+ new CipherSuite(0xc08d, "TLS_ECDH_RSA_WITH_CAMELLIA_256_GCM_SHA384"),
+ new CipherSuite(0xc08e, "TLS_PSK_WITH_CAMELLIA_128_GCM_SHA256"),
+ new CipherSuite(0xc08f, "TLS_PSK_WITH_CAMELLIA_256_GCM_SHA384"),
+ new CipherSuite(0xc090, "TLS_DHE_PSK_WITH_CAMELLIA_128_GCM_SHA256"),
+ new CipherSuite(0xc091, "TLS_DHE_PSK_WITH_CAMELLIA_256_GCM_SHA384"),
+ new CipherSuite(0xc092, "TLS_RSA_PSK_WITH_CAMELLIA_128_GCM_SHA256"),
+ new CipherSuite(0xc093, "TLS_RSA_PSK_WITH_CAMELLIA_256_GCM_SHA384"),
+ new CipherSuite(0xc094, "TLS_PSK_WITH_CAMELLIA_128_CBC_SHA256"),
+ new CipherSuite(0xc095, "TLS_PSK_WITH_CAMELLIA_256_CBC_SHA384"),
+ new CipherSuite(0xc096, "TLS_DHE_PSK_WITH_CAMELLIA_128_CBC_SHA256"),
+ new CipherSuite(0xc097, "TLS_DHE_PSK_WITH_CAMELLIA_256_CBC_SHA384"),
+ new CipherSuite(0xc098, "TLS_RSA_PSK_WITH_CAMELLIA_128_CBC_SHA256"),
+ new CipherSuite(0xc099, "TLS_RSA_PSK_WITH_CAMELLIA_256_CBC_SHA384"),
+ new CipherSuite(0xc09a, "TLS_ECDHE_PSK_WITH_CAMELLIA_128_CBC_SHA256"),
+ new CipherSuite(0xc09b, "TLS_ECDHE_PSK_WITH_CAMELLIA_256_CBC_SHA384"),
+ new CipherSuite(0xc09c, "TLS_RSA_WITH_AES_128_CCM"),
+ new CipherSuite(0xc09d, "TLS_RSA_WITH_AES_256_CCM"),
+ new CipherSuite(0xc09e, "TLS_DHE_RSA_WITH_AES_128_CCM"),
+ new CipherSuite(0xc09f, "TLS_DHE_RSA_WITH_AES_256_CCM"),
+ new CipherSuite(0xc0a0, "TLS_RSA_WITH_AES_128_CCM_8"),
+ new CipherSuite(0xc0a1, "TLS_RSA_WITH_AES_256_CCM_8"),
+ new CipherSuite(0xc0a2, "TLS_DHE_RSA_WITH_AES_128_CCM_8"),
+ new CipherSuite(0xc0a3, "TLS_DHE_RSA_WITH_AES_256_CCM_8"),
+ new CipherSuite(0xc0a4, "TLS_PSK_WITH_AES_128_CCM"),
+ new CipherSuite(0xc0a5, "TLS_PSK_WITH_AES_256_CCM"),
+ new CipherSuite(0xc0a6, "TLS_DHE_PSK_WITH_AES_128_CCM"),
+ new CipherSuite(0xc0a7, "TLS_DHE_PSK_WITH_AES_256_CCM"),
+ new CipherSuite(0xc0a8, "TLS_PSK_WITH_AES_128_CCM_8"),
+ new CipherSuite(0xc0a9, "TLS_PSK_WITH_AES_256_CCM_8"),
+ new CipherSuite(0xc0aa, "TLS_PSK_DHE_WITH_AES_128_CCM_8"),
+ new CipherSuite(0xc0ab, "TLS_PSK_DHE_WITH_AES_256_CCM_8"),
+ new CipherSuite(0xc0ac, "TLS_ECDHE_ECDSA_WITH_AES_128_CCM"),
+ new CipherSuite(0xc0ad, "TLS_ECDHE_ECDSA_WITH_AES_256_CCM"),
+ new CipherSuite(0xc0ae, "TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8"),
+ new CipherSuite(0xc0af, "TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8"),
+ new CipherSuite(0xcc13, "TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305"),
+ new CipherSuite(0xcc14, "TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305"),
+ new CipherSuite(0xcc15, "TLS_DHE_RSA_WITH_CHACHA20_POLY1305"),
+ };
+
+ private static final Map<Integer, CipherSuite> CODE_TO_CIPHER_SUITE;
+ private static final Map<String, CipherSuite> NAME_TO_CIPHER_SUITE;
+
+
+ static {
+ Map<Integer, CipherSuite> byCode = new HashMap<Integer, CipherSuite>();
+ Map<String, CipherSuite> byName = new HashMap<String, CipherSuite>();
+ for (CipherSuite cipherSuite : CIPHER_SUITES) {
+ if (byCode.put(cipherSuite.code, cipherSuite) != null) {
+ throw new RuntimeException(
+ "Cipher suite multiply defined: " + Integer.toHexString(cipherSuite.code));
+ }
+ String name = cipherSuite.name;
+ if (byName.put(name, cipherSuite) != null) {
+ throw new RuntimeException(
+ "Cipher suite multiply defined: " + cipherSuite.name);
+ }
+ String androidName = cipherSuite.getAndroidName();
+ if (!name.equals(androidName)) {
+ if (byName.put(androidName, cipherSuite) != null) {
+ throw new RuntimeException(
+ "Cipher suite multiply defined: " + cipherSuite.androidName);
+ }
+ }
+ }
+
+ CODE_TO_CIPHER_SUITE = byCode;
+ NAME_TO_CIPHER_SUITE = byName;
+ }
+
+ public final int code;
+ public final String name;
+ private final String androidName;
+
+ private CipherSuite(int code, String name) {
+ this.code = code;
+ this.name = name;
+ this.androidName = null;
+ }
+
+ private CipherSuite(int code, String name, String androidName) {
+ this.code = code;
+ this.name = name;
+ this.androidName = androidName;
+ }
+
+ public static CipherSuite valueOf(String name) {
+ CipherSuite result = NAME_TO_CIPHER_SUITE.get(name);
+ if (result != null) {
+ return result;
+ }
+ throw new IllegalArgumentException("Unknown cipher suite: " + name);
+ }
+
+ public static CipherSuite valueOf(int code) {
+ CipherSuite result = CODE_TO_CIPHER_SUITE.get(code);
+ if (result != null) {
+ return result;
+ }
+ return new CipherSuite(code, Integer.toHexString(code));
+ }
+
+ public String getAndroidName() {
+ return (androidName != null) ? androidName : name;
+ }
+
+ @Override
+ public String toString() {
+ return name;
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + code;
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj == null) {
+ return false;
+ }
+ if (getClass() != obj.getClass()) {
+ return false;
+ }
+ CipherSuite other = (CipherSuite) obj;
+ if (code != other.code) {
+ return false;
+ }
+ return true;
+ }
+}
diff --git a/support/src/test/java/libcore/tlswire/handshake/ClientHello.java b/support/src/test/java/libcore/tlswire/handshake/ClientHello.java
new file mode 100644
index 0000000..ec88662
--- /dev/null
+++ b/support/src/test/java/libcore/tlswire/handshake/ClientHello.java
@@ -0,0 +1,108 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package libcore.tlswire.handshake;
+
+import libcore.tlswire.util.TlsProtocolVersion;
+import libcore.tlswire.util.IoUtils;
+import libcore.util.HexEncoding;
+import java.io.ByteArrayInputStream;
+import java.io.DataInput;
+import java.io.DataInputStream;
+import java.io.EOFException;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * {@link ClientHello} {@link HandshakeMessage} from TLS 1.2 RFC 5246.
+ */
+public class ClientHello extends HandshakeMessage {
+ public TlsProtocolVersion clientVersion;
+ public byte[] random;
+ public byte[] sessionId;
+ public List<CipherSuite> cipherSuites;
+ public List<CompressionMethod> compressionMethods;
+
+ /** Extensions or {@code null} for no extensions. */
+ public List<HelloExtension> extensions;
+
+ @Override
+ protected void parseBody(DataInput in) throws IOException {
+ clientVersion = TlsProtocolVersion.read(in);
+ random = new byte[32];
+ in.readFully(random);
+ sessionId = IoUtils.readTlsVariableLengthByteVector(in, 32);
+ int[] cipherSuiteCodes = IoUtils.readTlsVariableLengthUnsignedShortVector(in, 0xfffe);
+ cipherSuites = new ArrayList<CipherSuite>(cipherSuiteCodes.length);
+ for (int i = 0; i < cipherSuiteCodes.length; i++) {
+ cipherSuites.add(CipherSuite.valueOf(cipherSuiteCodes[i]));
+ }
+ byte[] compressionMethodCodes = IoUtils.readTlsVariableLengthByteVector(in, 0xff);
+ compressionMethods = new ArrayList<CompressionMethod>(compressionMethodCodes.length);
+ for (int i = 0; i < compressionMethodCodes.length; i++) {
+ int code = compressionMethodCodes[i] & 0xff;
+ compressionMethods.add(CompressionMethod.valueOf(code));
+ }
+
+ int extensionsSectionSize;
+ try {
+ extensionsSectionSize = in.readUnsignedShort();
+ } catch (EOFException e) {
+ // No extensions present
+ extensionsSectionSize = 0;
+ }
+
+ if (extensionsSectionSize > 0) {
+ extensions = new ArrayList<HelloExtension>();
+ byte[] extensionsBytes = new byte[extensionsSectionSize];
+ in.readFully(extensionsBytes);
+ ByteArrayInputStream extensionsIn = new ByteArrayInputStream(extensionsBytes);
+ DataInput extensionsDataIn = new DataInputStream(extensionsIn);
+ while (extensionsIn.available() > 0) {
+ try {
+ extensions.add(HelloExtension.read(extensionsDataIn));
+ } catch (IOException e) {
+ throw new IOException(
+ "Failed to read HelloExtension #" + (extensions.size() + 1));
+ }
+ }
+ }
+ }
+
+ public HelloExtension findExtensionByType(int extensionType) {
+ if (extensions == null) {
+ return null;
+ }
+ for (HelloExtension extension : extensions) {
+ if (extension.type == extensionType) {
+ return extension;
+ }
+ }
+ return null;
+ }
+
+ @Override
+ public String toString() {
+ return "ClientHello{client version: " + clientVersion
+ + ", random: " + new String(HexEncoding.encode(random))
+ + ", sessionId: " + new String(HexEncoding.encode(sessionId))
+ + ", cipher suites: " + cipherSuites
+ + ", compression methods: " + compressionMethods
+ + ((extensions != null) ? (", extensions: " + String.valueOf(extensions)) : "")
+ + "}";
+ }
+}
diff --git a/support/src/test/java/libcore/tlswire/handshake/CompressionMethod.java b/support/src/test/java/libcore/tlswire/handshake/CompressionMethod.java
new file mode 100644
index 0000000..0f4f619
--- /dev/null
+++ b/support/src/test/java/libcore/tlswire/handshake/CompressionMethod.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package libcore.tlswire.handshake;
+
+/**
+ * {@code CompressionMethod} enum from TLS 1.2 RFC 5246.
+ */
+public class CompressionMethod {
+
+ public static final CompressionMethod NULL = new CompressionMethod(0, "null");
+ public static final CompressionMethod DEFLATE = new CompressionMethod(1, "deflate");
+
+ public final int type;
+ public final String name;
+
+ private CompressionMethod(int type, String name) {
+ this.type = type;
+ this.name = name;
+ }
+
+ public static CompressionMethod valueOf(int type) {
+ switch (type) {
+ case 0:
+ return NULL;
+ case 1:
+ return DEFLATE;
+ default:
+ return new CompressionMethod(type, String.valueOf(type));
+ }
+ }
+
+ @Override
+ public String toString() {
+ return name;
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + type;
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj == null) {
+ return false;
+ }
+ if (getClass() != obj.getClass()) {
+ return false;
+ }
+ CompressionMethod other = (CompressionMethod) obj;
+ if (type != other.type) {
+ return false;
+ }
+ return true;
+ }
+}
diff --git a/support/src/test/java/libcore/tlswire/handshake/HandshakeMessage.java b/support/src/test/java/libcore/tlswire/handshake/HandshakeMessage.java
new file mode 100644
index 0000000..a855b46
--- /dev/null
+++ b/support/src/test/java/libcore/tlswire/handshake/HandshakeMessage.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package libcore.tlswire.handshake;
+
+import libcore.tlswire.util.IoUtils;
+import java.io.ByteArrayInputStream;
+import java.io.DataInput;
+import java.io.DataInputStream;
+import java.io.IOException;
+
+/**
+ * Handshake Protocol message from TLS 1.2 RFC 5246.
+ */
+public class HandshakeMessage {
+ public static final int TYPE_CLIENT_HELLO = 1;
+
+ public int type;
+ public byte[] body;
+
+ /**
+ * Parses the provided TLS record as a handshake message.
+ */
+ public static HandshakeMessage read(DataInput in) throws IOException {
+ int type = in.readUnsignedByte();
+ HandshakeMessage result;
+ switch (type) {
+ case TYPE_CLIENT_HELLO:
+ result = new ClientHello();
+ break;
+ default:
+ result = new HandshakeMessage();
+ break;
+ }
+ result.type = type;
+ int bodyLength = IoUtils.readUnsignedInt24(in);
+ result.body = new byte[bodyLength];
+ in.readFully(result.body);
+ result.parseBody(new DataInputStream(new ByteArrayInputStream(result.body)));
+ return result;
+ }
+
+ /**
+ * Parses the provided body. The default implementation does nothing.
+ *
+ * @throws IOException if an I/O error occurs.
+ */
+ protected void parseBody(@SuppressWarnings("unused") DataInput in) throws IOException {}
+}
diff --git a/support/src/test/java/libcore/tlswire/handshake/HelloExtension.java b/support/src/test/java/libcore/tlswire/handshake/HelloExtension.java
new file mode 100644
index 0000000..5741072
--- /dev/null
+++ b/support/src/test/java/libcore/tlswire/handshake/HelloExtension.java
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package libcore.tlswire.handshake;
+
+import libcore.tlswire.util.IoUtils;
+import libcore.util.HexEncoding;
+import java.io.DataInput;
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * {@code HelloExtension} struct from TLS 1.2 RFC 5246.
+ */
+public class HelloExtension {
+
+ public static final int TYPE_SERVER_NAME = 0;
+ public static final int TYPE_PADDING = 21;
+ public static final int TYPE_SESSION_TICKET = 35;
+
+ private static final Map<Integer, String> TYPE_TO_NAME = new HashMap<Integer, String>();
+ static {
+ TYPE_TO_NAME.put(TYPE_SERVER_NAME, "server_name");
+ TYPE_TO_NAME.put(1, "max_fragment_length");
+ TYPE_TO_NAME.put(2, "client_certificate_url");
+ TYPE_TO_NAME.put(3, "trusted_ca_keys");
+ TYPE_TO_NAME.put(4, "truncated_hmac");
+ TYPE_TO_NAME.put(5, "status_request");
+ TYPE_TO_NAME.put(6, "user_mapping");
+ TYPE_TO_NAME.put(7, "client_authz");
+ TYPE_TO_NAME.put(8, "server_authz");
+ TYPE_TO_NAME.put(9, "cert_type");
+ TYPE_TO_NAME.put(10, "elliptic_curves");
+ TYPE_TO_NAME.put(11, "ec_point_formats");
+ TYPE_TO_NAME.put(12, "srp");
+ TYPE_TO_NAME.put(13, "signature_algorithms");
+ TYPE_TO_NAME.put(14, "use_srtp");
+ TYPE_TO_NAME.put(15, "heartbeat");
+ TYPE_TO_NAME.put(16, "application_layer_protocol_negotiation");
+ TYPE_TO_NAME.put(17, "status_request_v2");
+ TYPE_TO_NAME.put(18, "signed_certificate_timestamp");
+ TYPE_TO_NAME.put(19, "client_certificate_type");
+ TYPE_TO_NAME.put(20, "server_certificate_type");
+ TYPE_TO_NAME.put(TYPE_PADDING, "padding");
+ TYPE_TO_NAME.put(TYPE_SESSION_TICKET, "SessionTicket");
+ TYPE_TO_NAME.put(13172, "next_protocol_negotiation");
+ TYPE_TO_NAME.put(30031, "Channel ID (old)");
+ TYPE_TO_NAME.put(30032, "Channel ID (new)");
+ TYPE_TO_NAME.put(65281, "renegotiation_info");
+ }
+
+ public int type;
+ public String name;
+ public byte[] data;
+
+ public static HelloExtension read(DataInput in) throws IOException {
+ int type = in.readUnsignedShort();
+ HelloExtension result;
+ switch (type) {
+ case TYPE_SERVER_NAME:
+ result = new ServerNameHelloExtension();
+ break;
+ default:
+ result = new HelloExtension();
+ break;
+ }
+ result.type = type;
+ result.name = TYPE_TO_NAME.get(result.type);
+ if (result.name == null) {
+ result.name = String.valueOf(result.type);
+ }
+ result.data = IoUtils.readTlsVariableLengthByteVector(in, 0xffff);
+ result.parseData();
+ return result;
+ }
+
+ /**
+ * @throws IOException
+ */
+ protected void parseData() throws IOException {}
+
+ @Override
+ public String toString() {
+ return "HelloExtension{type: " + name + ", data: " + HexEncoding.encode(data) + "}";
+ }
+}
diff --git a/support/src/test/java/libcore/tlswire/handshake/ServerNameHelloExtension.java b/support/src/test/java/libcore/tlswire/handshake/ServerNameHelloExtension.java
new file mode 100644
index 0000000..5b06246
--- /dev/null
+++ b/support/src/test/java/libcore/tlswire/handshake/ServerNameHelloExtension.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package libcore.tlswire.handshake;
+
+import libcore.tlswire.util.IoUtils;
+import java.io.ByteArrayInputStream;
+import java.io.DataInputStream;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * {@code server_name} (SNI) {@link HelloExtension} from TLS 1.2 RFC 5246.
+ */
+public class ServerNameHelloExtension extends HelloExtension {
+ private static final int TYPE_HOST_NAME = 0;
+
+ public List<String> hostnames;
+
+ @Override
+ protected void parseData() throws IOException {
+ byte[] serverNameListBytes = IoUtils.readTlsVariableLengthByteVector(
+ new DataInputStream(new ByteArrayInputStream(data)), 0xffff);
+ ByteArrayInputStream serverNameListIn = new ByteArrayInputStream(serverNameListBytes);
+ DataInputStream in = new DataInputStream(serverNameListIn);
+ hostnames = new ArrayList<String>();
+ while (serverNameListIn.available() > 0) {
+ int type = in.readUnsignedByte();
+ if (type != TYPE_HOST_NAME) {
+ throw new IOException("Unsupported ServerName type: " + type);
+ }
+ byte[] hostnameBytes = IoUtils.readTlsVariableLengthByteVector(in, 0xffff);
+ String hostname = new String(hostnameBytes, "US-ASCII");
+ hostnames.add(hostname);
+ }
+ }
+
+ @Override
+ public String toString() {
+ return "HelloExtension{type: server_name, hostnames: " + hostnames + "}";
+ }
+}
diff --git a/support/src/test/java/libcore/tlswire/record/TlsProtocols.java b/support/src/test/java/libcore/tlswire/record/TlsProtocols.java
new file mode 100644
index 0000000..0ce0d35
--- /dev/null
+++ b/support/src/test/java/libcore/tlswire/record/TlsProtocols.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package libcore.tlswire.record;
+
+/**
+ * Protocols that can run over the TLS Record Protocol from TLS 1.2 RFC 5246.
+ */
+public class TlsProtocols {
+ public static final int CHANGE_CIPHER_SPEC = 20;
+ public static final int ALERT = 21;
+ public static final int HANDSHAKE = 22;
+ public static final int APPLICATION_DATA = 23;
+ public static final int HEARTBEAT = 24;
+
+ private TlsProtocols() {}
+}
diff --git a/support/src/test/java/libcore/tlswire/record/TlsRecord.java b/support/src/test/java/libcore/tlswire/record/TlsRecord.java
new file mode 100644
index 0000000..1b60407
--- /dev/null
+++ b/support/src/test/java/libcore/tlswire/record/TlsRecord.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package libcore.tlswire.record;
+
+import libcore.tlswire.util.TlsProtocolVersion;
+import java.io.DataInput;
+import java.io.IOException;
+
+/**
+ * TLS Record Protocol record from TLS 1.2 RFC 5246.
+ */
+public class TlsRecord {
+ public int type;
+ public TlsProtocolVersion version;
+ public byte[] fragment;
+
+ public static TlsRecord read(DataInput in) throws IOException {
+ TlsRecord result = new TlsRecord();
+ result.type = in.readUnsignedByte();
+ result.version = TlsProtocolVersion.read(in);
+ int fragmentLength = in.readUnsignedShort();
+ result.fragment = new byte[fragmentLength];
+ in.readFully(result.fragment);
+ return result;
+ }
+}
diff --git a/support/src/test/java/libcore/tlswire/util/IoUtils.java b/support/src/test/java/libcore/tlswire/util/IoUtils.java
new file mode 100644
index 0000000..1e2d8f2
--- /dev/null
+++ b/support/src/test/java/libcore/tlswire/util/IoUtils.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package libcore.tlswire.util;
+
+import java.io.DataInput;
+import java.io.IOException;
+
+public class IoUtils {
+
+ public static int readUnsignedInt24(DataInput in) throws IOException {
+ return (in.readUnsignedByte() << 16) | in.readUnsignedShort();
+ }
+
+ public static byte[] readTlsVariableLengthByteVector(DataInput in, int maxSizeBytes)
+ throws IOException {
+ int sizeBytes = readTlsVariableLengthVectorSizeBytes(in, maxSizeBytes);
+ byte[] result = new byte[sizeBytes];
+ in.readFully(result);
+ return result;
+ }
+
+ public static int[] readTlsVariableLengthUnsignedShortVector(DataInput in, int maxSizeBytes)
+ throws IOException {
+ int sizeBytes = readTlsVariableLengthVectorSizeBytes(in, maxSizeBytes);
+ int elementCount = sizeBytes / 2;
+ int[] result = new int[elementCount];
+ for (int i = 0; i < elementCount; i++) {
+ result[i] = in.readUnsignedShort();
+ }
+ return result;
+ }
+
+ private static int readTlsVariableLengthVectorSizeBytes(DataInput in, int maxSizeBytes)
+ throws IOException {
+ if (maxSizeBytes < 0x100) {
+ return in.readUnsignedByte();
+ } else if (maxSizeBytes < 0x10000) {
+ return in.readUnsignedShort();
+ } else if (maxSizeBytes < 0x1000000) {
+ return readUnsignedInt24(in);
+ } else {
+ return in.readInt();
+ }
+ }
+}
diff --git a/support/src/test/java/libcore/tlswire/util/TlsProtocolVersion.java b/support/src/test/java/libcore/tlswire/util/TlsProtocolVersion.java
new file mode 100644
index 0000000..f58faf2
--- /dev/null
+++ b/support/src/test/java/libcore/tlswire/util/TlsProtocolVersion.java
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package libcore.tlswire.util;
+
+import java.io.DataInput;
+import java.io.IOException;
+
+/**
+ * {@code ProtovolVersion} struct from TLS 1.2 RFC 5246.
+ */
+public class TlsProtocolVersion {
+ public static final TlsProtocolVersion SSLV3 = new TlsProtocolVersion(3, 0, "SSLv3");
+ public static final TlsProtocolVersion TLSv1_0 = new TlsProtocolVersion(3, 1, "TLSv1.0");
+ public static final TlsProtocolVersion TLSv1_1 = new TlsProtocolVersion(3, 2, "TLSv1.1");
+ public static final TlsProtocolVersion TLSv1_2 = new TlsProtocolVersion(3, 3, "TLSv1.2");
+
+ public final int major;
+ public final int minor;
+ public final String name;
+
+ private TlsProtocolVersion(int major, int minor, String name) {
+ this.major = major;
+ this.minor = minor;
+ this.name = name;
+ }
+
+ public static TlsProtocolVersion valueOf(int major, int minor) {
+ if (major == 3) {
+ switch (minor) {
+ case 0:
+ return SSLV3;
+ case 1:
+ return TLSv1_0;
+ case 2:
+ return TLSv1_1;
+ case 3:
+ return TLSv1_2;
+ }
+ }
+ return new TlsProtocolVersion(major, minor, major + "." + minor);
+ }
+
+ public static TlsProtocolVersion read(DataInput in) throws IOException {
+ int major = in.readUnsignedByte();
+ int minor = in.readUnsignedByte();
+ return TlsProtocolVersion.valueOf(major, minor);
+ }
+
+ @Override
+ public String toString() {
+ return name;
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + major;
+ result = prime * result + minor;
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj == null) {
+ return false;
+ }
+ if (getClass() != obj.getClass()) {
+ return false;
+ }
+ TlsProtocolVersion other = (TlsProtocolVersion) obj;
+ if (major != other.major) {
+ return false;
+ }
+ if (minor != other.minor) {
+ return false;
+ }
+ return true;
+ }
+}
diff --git a/support/src/test/java/tests/net/StuckServer.java b/support/src/test/java/tests/net/StuckServer.java
index f7a3118..d6b038b 100644
--- a/support/src/test/java/tests/net/StuckServer.java
+++ b/support/src/test/java/tests/net/StuckServer.java
@@ -21,6 +21,7 @@ import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.Socket;
+import java.net.UnknownHostException;
import java.util.ArrayList;
/**
@@ -29,6 +30,19 @@ import java.util.ArrayList;
public final class StuckServer {
private static final boolean DEBUG = false;
+ // RFC 5737 implies this network -- "test net 1" -- will be unreachable.
+ // (There are two other networks to try if we have trouble with this one.)
+ // We've had trouble with 10.* in the past (because test labs running CTS often use
+ // net 10!) but hopefully this network will be better.
+ public static final InetAddress UNREACHABLE_ADDRESS;
+ static {
+ try {
+ UNREACHABLE_ADDRESS = InetAddress.getByAddress(new byte[] { (byte) 192, 0, 2, 0 });
+ } catch (UnknownHostException ex) {
+ throw new AssertionError(ex);
+ }
+ }
+
private ServerSocket serverSocket;
private InetSocketAddress address;
private ArrayList<Socket> clients = new ArrayList<Socket>();
@@ -57,12 +71,7 @@ public final class StuckServer {
}
} else {
// In general, though, you don't want to rely on listen(2) backlog. http://b/6971145.
- // RFC 5737 implies this network will be unreachable. (There are two other networks
- // to try if we have trouble with this one.)
- // We've had trouble with 10.* in the past (because test labs running CTS often use
- // net 10!) but hopefully this network will be better.
- InetAddress testNet1 = InetAddress.getByAddress(new byte[] { (byte) 192, 0, 2, 0 });
- this.address = new InetSocketAddress(testNet1, 80);
+ this.address = new InetSocketAddress(UNREACHABLE_ADDRESS, 80);
}
}
diff --git a/support/src/test/java/tests/resources/removed.jar b/support/src/test/java/tests/resources/removed.jar
new file mode 100644
index 0000000..2100322
--- /dev/null
+++ b/support/src/test/java/tests/resources/removed.jar
Binary files differ
diff --git a/support/src/test/java/tests/support/Support_Configuration.java b/support/src/test/java/tests/support/Support_Configuration.java
index 313a448..0856d44 100644
--- a/support/src/test/java/tests/support/Support_Configuration.java
+++ b/support/src/test/java/tests/support/Support_Configuration.java
@@ -32,390 +32,35 @@ import java.util.Hashtable;
*/
public class Support_Configuration {
- public static String DomainAddress = "apache.org";
+ public static final String DomainAddress = "apache.org";
- public static String WebName = "jcltest.";
+ public static final String WebName = "jcltest.";
- public static final String HomeAddress;
+ public static final String HomeAddress = WebName + DomainAddress;
- public static String TestResourcesDir = "/testres231";
+ public static final String TestResourcesDir = "/testres231";
- public static final String TestResources;
+ public static final String TestResources = HomeAddress + TestResourcesDir;
- public static String HomeAddressResponse = "HTTP/1.1 200 OK";
+ public static final String HomeAddressResponse = "HTTP/1.1 200 OK";
- public static String HomeAddressSoftware = "Jetty(6.0.x)";
+ public static final String HomeAddressSoftware = "Jetty(6.0.x)";
- public static String SocksServerTestHost = "jcltest.apache.org";
+ public static final String SocksServerTestHost = "jcltest.apache.org";
- public static int SocksServerTestPort = 1080;
-
- // Need an IP address that does not resolve to a host name
- public static String UnresolvedIP = "192.168.99.99";
+ public static final int SocksServerTestPort = 1080;
// the bytes for an address which represents an address which is not
// one of the addresses for any of our machines on which tests will run
// it is used to verify we get the expected error when we try to bind
// to an address that is not one of the machines local addresses
- public static byte nonLocalAddressBytes[] = { 1, 0, 0, 0 };
-
- public static String InetTestAddress = "localhost";
-
- public static String InetTestIP = "127.0.0.1";
-
- // BEGIN android-added
- public static byte[] InetTestAddr = {127, 0, 0, 1};
- // END android-added
-
- public static String InetTestAddress2 = "localhost";
-
- public static String InetTestIP2 = "127.0.0.1";
-
- public static byte[] InetTestCaddr = { 9, 26, -56, -111 };
-
- public static String IPv6GlobalAddressJcl4 = "2001:4860:8004::67"; // ipv6.google.com
-
- // ip address that resolves to a host that is not present on the local
- // network
- // this allows us to check the timeouts for connect
- public static String ResolvedNotExistingHost = "9.26.194.72";
-
- // BEGIN android-changed
- /**
- * An address that resolves to more than one IP address so that the
- * getAllByName test has something to test.
- */
- public static String SpecialInetTestAddress = "www.google.com";
- // changed from jcltestmultiple.apache.org to www.google.com since
- // the old address vaished from the net. www.google.com has also more
- // than one addresses returned for this host name as needed by a test
- // END android-changed
-
- public static int SpecialInetTestAddressNumber = 4;
-
- /**
- * InetAlias1 and InetAlias2 must be different host names that resolve to
- * the same IP address.
- */
- public static String InetAlias1 = "alias1.apache.org";
-
- public static String InetAlias2 = "alias2.apache.org";
-
- public static String FTPTestAddress = "jcltest:jclpass@localhost";
-
- public static String URLConnectionLastModifiedString = "Mon, 14 Jun 1999 21:06:22 GMT";
-
- public static long URLConnectionLastModified = 929394382000L;
-
- public static long URLConnectionDate = 929106872000L;
-
- static Hashtable<String, String> props = null;
- static {
- loadProperties();
- HomeAddress = WebName + DomainAddress;
- TestResources = HomeAddress + TestResourcesDir;
- }
-
- static void loadProperties() {
- InputStream in = null;
- Hashtable<String, String> props = new Hashtable<String, String>();
-
- String iniName = System.getProperty("test.ini.file", "JCLAuto.ini");
-
- try {
- in = new FileInputStream(iniName);
- } catch (IOException e) {
- } catch (Exception e) {
- System.out.println("SupportConfiguration.loadProperties()");
- System.out.println(e);
- e.printStackTrace();
- }
- if (in == null) {
- try {
- Class<?> cl = Class
- .forName("com.ibm.support.Support_Configuration");
- in = cl.getResourceAsStream(iniName);
- } catch (ClassNotFoundException e) {
- }
- }
- try {
- if (in != null) {
- load(in, props);
- }
- } catch (IOException e) {
- }
- if (props.size() == 0) {
- return;
- }
- String value;
-
- value = props.get("DomainAddress");
- if (value != null) {
- DomainAddress = value;
- }
-
- value = props.get("WebName");
- if (value != null) {
- WebName = value;
- }
-
- value = props.get("TestResourcesDir");
- if (value != null) {
- TestResourcesDir = value;
- }
- value = props.get("HomeAddressResponse");
- if (value != null) {
- HomeAddressResponse = value;
- }
-
- value = props.get("HomeAddressSoftware");
- if (value != null) {
- HomeAddressSoftware = value;
- }
-
- value = props.get("SocksServerTestHost");
- if (value != null) {
- SocksServerTestHost = value;
- }
-
- value = props.get("SocksServerTestPort");
- if (value != null) {
- SocksServerTestPort = Integer.parseInt(value);
- }
-
- value = props.get("UnresolvedIP");
- if (value != null) {
- UnresolvedIP = value;
- }
-
- value = props.get("InetTestAddress");
- if (value != null) {
- InetTestAddress = value;
- }
-
- value = props.get("InetTestIP");
- if (value != null) {
- InetTestIP = value;
- byte[] addr = new byte[4];
- int last = 0;
- try {
- for (int i = 0; i < 3; i++) {
- int dot = InetTestIP.indexOf('.', last);
- addr[i] = (byte) Integer.parseInt(InetTestIP.substring(
- last, dot));
- last = dot + 1;
- }
- addr[3] = (byte) Integer.parseInt(InetTestIP.substring(last));
- InetTestCaddr = addr;
- } catch (RuntimeException e) {
- System.out.println("Error parsing InetTestIP (" + InetTestIP
- + ")");
- System.out.println(e);
- }
- }
-
- value = props.get("NonLocalAddressBytes");
- if (value != null) {
- String nonLocalAddressBytesString = value;
- byte[] addr = new byte[4];
- int last = 0;
- try {
- for (int i = 0; i < 3; i++) {
- int dot = nonLocalAddressBytesString.indexOf('.', last);
- addr[i] = (byte) Integer
- .parseInt(nonLocalAddressBytesString.substring(
- last, dot));
- last = dot + 1;
- }
- addr[3] = (byte) Integer.parseInt(nonLocalAddressBytesString
- .substring(last));
- nonLocalAddressBytes = addr;
- } catch (RuntimeException e) {
- System.out.println("Error parsing NonLocalAddressBytes ("
- + nonLocalAddressBytesString + ")");
- System.out.println(e);
- }
- }
-
- value = props.get("InetTestAddress2");
- if (value != null) {
- InetTestAddress2 = value;
- }
-
- value = props.get("InetTestIP2");
- if (value != null) {
- InetTestIP2 = value;
- }
-
- value = props.get("SpecialInetTestAddress");
- if (value != null) {
- SpecialInetTestAddress = value;
- }
-
- value = props.get("SpecialInetTestAddressNumber");
- if (value != null) {
- SpecialInetTestAddressNumber = Integer.parseInt(value);
- }
-
- value = props.get("FTPTestAddress");
- if (value != null) {
- FTPTestAddress = value;
- }
-
- value = props.get("URLConnectionLastModifiedString");
- if (value != null) {
- URLConnectionLastModifiedString = value;
- }
-
- value = props.get("URLConnectionLastModified");
- if (value != null) {
- URLConnectionLastModified = Long.parseLong(value);
- }
-
- value = props.get("URLConnectionDate");
- if (value != null) {
- URLConnectionDate = Long.parseLong(value);
- }
-
- value = props.get("ResolvedNotExistingHost");
- if (value != null) {
- ResolvedNotExistingHost = value;
- }
-
- value = props.get("InetAlias1");
- if (value != null) {
- InetAlias1 = value;
- }
-
- value = props.get("InetAlias2");
- if (value != null) {
- InetAlias2 = value;
- }
-
- value = props.get("IPv6GlobalAddressJcl4");
- if (value != null) {
- IPv6GlobalAddressJcl4 = value;
- }
+ public static final byte nonLocalAddressBytes[] = { 1, 0, 0, 0 };
- }
+ public static final String FTPTestAddress = "jcltest:jclpass@localhost";
- static void load(InputStream in, Hashtable<String, String> result) throws IOException {
- int NONE = 0, SLASH = 1, UNICODE = 2, CONTINUE = 3, DONE = 4, IGNORE = 5;
- int mode = NONE, unicode = 0, count = 0, nextChar;
- StringBuffer key = new StringBuffer(), value = new StringBuffer(), buffer = key;
- boolean firstChar = true;
+ public static final String URLConnectionLastModifiedString = "Mon, 14 Jun 1999 21:06:22 GMT";
- while ((nextChar = in.read()) != -1) {
- if (mode == UNICODE) {
- int digit = Character.digit((char) nextChar, 16);
- if (digit >= 0) {
- unicode = (unicode << 4) + digit;
- if (++count < 4) {
- continue;
- }
- }
- mode = NONE;
- buffer.append((char) unicode);
- if (nextChar != '\n') {
- continue;
- }
- }
- if (mode == SLASH) {
- mode = NONE;
- switch (nextChar) {
- case '\r':
- mode = CONTINUE; // Look for a following \n
- continue;
- case '\n':
- mode = IGNORE; // Ignore whitespace on the next line
- continue;
- case 'b':
- nextChar = '\b';
- break;
- case 'f':
- nextChar = '\f';
- break;
- case 'n':
- nextChar = '\n';
- break;
- case 'r':
- nextChar = '\r';
- break;
- case 't':
- nextChar = '\t';
- break;
- case 'u':
- mode = UNICODE;
- unicode = count = 0;
- continue;
- }
- } else {
- switch (nextChar) {
- case '#':
- case '!':
- if (firstChar) {
- while ((nextChar = in.read()) != -1) {
- if (nextChar == '\r' || nextChar == '\n') {
- break;
- }
- }
- continue;
- }
- break;
- case '\n':
- if (mode == CONTINUE) { // Part of a \r\n sequence
- mode = IGNORE; // Ignore whitespace on the next line
- continue;
- }
- // fall into the next case
- case '\r':
- mode = NONE;
- firstChar = true;
- if (key.length() > 0 || buffer == value) {
- result.put(key.toString(), value.toString());
- }
- key.setLength(0);
- value.setLength(0);
- buffer = key;
- continue;
- case '\\':
- mode = SLASH;
- continue;
- case ':':
- case '=':
- if (buffer == key) {
- buffer = value;
- continue;
- }
- break;
- }
- char c = (char) nextChar;
- if ((c >= 0x1c && c <= 0x20) || (c >= 0x9 && c <= 0xd)) {
- if (mode == CONTINUE) {
- mode = IGNORE;
- }
- if (buffer.length() == 0 || mode == IGNORE) {
- continue;
- }
- if (buffer == key) {
- mode = DONE;
- continue;
- }
- }
- if (mode == IGNORE || mode == CONTINUE) {
- mode = NONE;
- }
- }
- firstChar = false;
- if (mode == DONE) {
- buffer = value;
- mode = NONE;
- }
- buffer.append((char) nextChar);
- }
- if (key.length() > 0 || buffer == value) {
- result.put(key.toString(), value.toString());
- }
- }
+ public static final long URLConnectionLastModified = 929394382000L;
+ public static final long URLConnectionDate = 929106872000L;
}
diff --git a/support/src/test/java/tests/util/DelegatingSSLSocketFactory.java b/support/src/test/java/tests/util/DelegatingSSLSocketFactory.java
new file mode 100644
index 0000000..5513210
--- /dev/null
+++ b/support/src/test/java/tests/util/DelegatingSSLSocketFactory.java
@@ -0,0 +1,101 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package tests.util;
+
+import java.io.IOException;
+import java.net.InetAddress;
+import java.net.Socket;
+import java.net.UnknownHostException;
+
+import javax.net.ssl.SSLSocket;
+import javax.net.ssl.SSLSocketFactory;
+
+/**
+ * {@link SSLSocketFactory} which delegates all invocations to the provided delegate
+ * {@code SSLSocketFactory}.
+ */
+public class DelegatingSSLSocketFactory extends SSLSocketFactory {
+
+ private final SSLSocketFactory mDelegate;
+
+ public DelegatingSSLSocketFactory(SSLSocketFactory delegate) {
+ this.mDelegate = delegate;
+ }
+
+ /**
+ * Invoked after obtaining a socket from the delegate and before returning it to the caller.
+ *
+ * <p>The default implementation does nothing.
+ */
+ protected void configureSocket(@SuppressWarnings("unused") SSLSocket socket) {}
+
+ @Override
+ public String[] getDefaultCipherSuites() {
+ return mDelegate.getDefaultCipherSuites();
+ }
+
+ @Override
+ public String[] getSupportedCipherSuites() {
+ return mDelegate.getSupportedCipherSuites();
+ }
+
+ @Override
+ public Socket createSocket() throws IOException {
+ SSLSocket socket = (SSLSocket) mDelegate.createSocket();
+ configureSocket(socket);
+ return socket;
+ }
+
+ @Override
+ public Socket createSocket(Socket s, String host, int port, boolean autoClose)
+ throws IOException {
+ SSLSocket socket = (SSLSocket) mDelegate.createSocket(s, host, port, autoClose);
+ configureSocket(socket);
+ return socket;
+ }
+
+ @Override
+ public Socket createSocket(String host, int port) throws IOException, UnknownHostException {
+ SSLSocket socket = (SSLSocket) mDelegate.createSocket(host, port);
+ configureSocket(socket);
+ return socket;
+ }
+
+ @Override
+ public Socket createSocket(String host, int port, InetAddress localHost, int localPort)
+ throws IOException, UnknownHostException {
+ SSLSocket socket = (SSLSocket) mDelegate.createSocket(host, port, localHost, localPort);
+ configureSocket(socket);
+ return socket;
+ }
+
+ @Override
+ public Socket createSocket(InetAddress host, int port) throws IOException {
+ SSLSocket socket = (SSLSocket) mDelegate.createSocket(host, port);
+ configureSocket(socket);
+ return socket;
+ }
+
+ @Override
+ public Socket createSocket(InetAddress address, int port, InetAddress localAddress,
+ int localPort) throws IOException {
+ SSLSocket socket =
+ (SSLSocket) mDelegate.createSocket(address, port, localAddress, localPort);
+ configureSocket(socket);
+ return socket;
+ }
+}
diff --git a/support/src/test/java/tests/util/ForEachRunner.java b/support/src/test/java/tests/util/ForEachRunner.java
new file mode 100644
index 0000000..2c222b2
--- /dev/null
+++ b/support/src/test/java/tests/util/ForEachRunner.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package tests.util;
+
+/**
+ * Runner which executes the provided code under test (via a callback) for each provided input
+ * value.
+ */
+public final class ForEachRunner {
+
+ /**
+ * Callback parameterized with a value.
+ */
+ public interface Callback<T> {
+ /**
+ * Invokes the callback for the provided value.
+ */
+ void run(T value) throws Exception;
+ }
+
+ private ForEachRunner() {}
+
+ /**
+ * Invokes the provided callback for each of the provided named values.
+ *
+ * @param namesAndValues named values represented as name-value pairs.
+ *
+ * @param <T> type of value.
+ */
+ public static <T> void runNamed(Callback<T> callback, Iterable<Pair<String, T>> namesAndValues)
+ throws Exception {
+ for (Pair<String, T> nameAndValue : namesAndValues) {
+ try {
+ callback.run(nameAndValue.getSecond());
+ } catch (Throwable e) {
+ throw new Exception("Failed for " + nameAndValue.getFirst() + ": " + e.getMessage(), e);
+ }
+ }
+ }
+}
diff --git a/support/src/test/java/tests/util/Pair.java b/support/src/test/java/tests/util/Pair.java
new file mode 100644
index 0000000..9b0906d
--- /dev/null
+++ b/support/src/test/java/tests/util/Pair.java
@@ -0,0 +1,107 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package tests.util;
+
+/**
+ * Pair of typed values.
+ *
+ * <p>Pairs are obtained using {@link #of(Object, Object) of}.
+ *
+ * @param <F> type of the first value.
+ * @param <S> type of the second value.
+ */
+public class Pair<F, S> {
+ private final F mFirst;
+ private final S mSecond;
+
+ private Pair(F first, S second) {
+ mFirst = first;
+ mSecond = second;
+ }
+
+ /**
+ * Gets the pair consisting of the two provided values.
+ *
+ * @param first first value or {@code null}.
+ * @param second second value or {@code null}.
+ */
+ public static <F, S> Pair<F, S> of(F first, S second) {
+ return new Pair<F, S>(first, second);
+ }
+
+ /**
+ * Gets the first value from this pair.
+ *
+ * @return value or {@code null}.
+ */
+ public F getFirst() {
+ return mFirst;
+ }
+
+ /**
+ * Gets the second value from this pair.
+ *
+ * @return value or {@code null}.
+ */
+ public S getSecond() {
+ return mSecond;
+ }
+
+ @Override
+ public String toString() {
+ return "Pair[" + mFirst + ", " + mSecond + "]";
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + ((mFirst == null) ? 0 : mFirst.hashCode());
+ result = prime * result + ((mSecond == null) ? 0 : mSecond.hashCode());
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj == null) {
+ return false;
+ }
+ if (getClass() != obj.getClass()) {
+ return false;
+ }
+ @SuppressWarnings("rawtypes")
+ Pair other = (Pair) obj;
+ if (mFirst == null) {
+ if (other.mFirst != null) {
+ return false;
+ }
+ } else if (!mFirst.equals(other.mFirst)) {
+ return false;
+ }
+ if (mSecond == null) {
+ if (other.mSecond != null) {
+ return false;
+ }
+ } else if (!mSecond.equals(other.mSecond)) {
+ return false;
+ }
+ return true;
+ }
+}
diff --git a/support/src/test/java/tests/util/SummaryStatistics.java b/support/src/test/java/tests/util/SummaryStatistics.java
new file mode 100644
index 0000000..4ce0a04
--- /dev/null
+++ b/support/src/test/java/tests/util/SummaryStatistics.java
@@ -0,0 +1,82 @@
+/*
+ * Copyright 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package tests.util;
+
+public class SummaryStatistics {
+ /** The number of values seen. */
+ private int numValues;
+
+ /** Sum of the values. */
+ private double sum;
+
+ /** Sum of the squares of the values added. */
+ private double squaresSum;
+
+ /** The previously added value. */
+ private double lastValue;
+
+ public SummaryStatistics() {
+ }
+
+ private double square(double value) {
+ return value * value;
+ }
+
+ /** Add a new value to the values seen. */
+ public void add(double value) {
+ sum += value - lastValue;
+ squaresSum += square(value) - square(lastValue);
+ numValues++;
+ lastValue = value;
+ }
+
+ /** Mean of the values seen. */
+ public double mean() {
+ return sum / numValues;
+ }
+
+ /** Variance of the values seen. */
+ public double var() {
+ return (squaresSum / numValues) - square(mean());
+ }
+
+ /** Standard deviation of the values seen. */
+ public double stddev() {
+ return Math.sqrt(var());
+ }
+
+ /** Coefficient of variation of the values seen. */
+ public double coeffVar() {
+ return stddev() / mean();
+ }
+
+ public String toString() {
+ StringBuilder sb = new StringBuilder("SummaryStatistics{");
+ sb.append("n=");
+ sb.append(numValues);
+ sb.append(",mean=");
+ sb.append(mean());
+ sb.append(",var=");
+ sb.append(var());
+ sb.append(",stddev=");
+ sb.append(stddev());
+ sb.append(",coeffVar=");
+ sb.append(coeffVar());
+ sb.append('}');
+ return sb.toString();
+ }
+}
diff --git a/tzdata/Android.mk b/tzdata/Android.mk
new file mode 100644
index 0000000..9da8832
--- /dev/null
+++ b/tzdata/Android.mk
@@ -0,0 +1,51 @@
+# Copyright (C) 2015 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+LOCAL_PATH:= $(call my-dir)
+
+# Subprojects with separate makefiles
+subdirs := update_test_app
+subdir_makefiles := $(call all-named-subdir-makefiles,$(subdirs))
+
+# Library of tools classes for tzdata updates. Not required on device, except in tests.
+include $(CLEAR_VARS)
+LOCAL_MODULE := tzdata_tools
+LOCAL_MODULE_TAGS := optional
+LOCAL_SRC_FILES := $(call all-java-files-under, tools/src/main)
+LOCAL_JAVACFLAGS := -encoding UTF-8
+LOCAL_STATIC_JAVA_LIBRARIES := tzdata_update
+LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
+include $(BUILD_STATIC_JAVA_LIBRARY)
+
+# Library of support classes for tzdata updates. Shared between update generation and
+# on-device code.
+include $(CLEAR_VARS)
+LOCAL_MODULE := tzdata_update
+LOCAL_MODULE_TAGS := optional
+LOCAL_SRC_FILES := $(call all-java-files-under, update/src/main)
+LOCAL_JAVACFLAGS := -encoding UTF-8
+LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
+include $(BUILD_STATIC_JAVA_LIBRARY)
+
+# Tests for tzdata_update code
+include $(CLEAR_VARS)
+LOCAL_MODULE := tzdata_update-tests
+LOCAL_MODULE_TAGS := optional
+LOCAL_SRC_FILES := $(call all-java-files-under, update/src/test)
+LOCAL_JAVACFLAGS := -encoding UTF-8
+LOCAL_STATIC_JAVA_LIBRARIES := tzdata_update tzdata_tools
+LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
+include $(BUILD_STATIC_JAVA_LIBRARY)
+
+include $(subdir_makefiles)
diff --git a/tzdata/tools/createIcuUpdateResources.sh b/tzdata/tools/createIcuUpdateResources.sh
new file mode 100755
index 0000000..2db7132
--- /dev/null
+++ b/tzdata/tools/createIcuUpdateResources.sh
@@ -0,0 +1,89 @@
+#!/bin/bash
+#
+# A script that generates an ICU data file containing just timezone rules data.
+# The file can be used to provide time zone rules updates for compatible
+# devices. Note: Only the rules are contained and new timezones will not have
+# the translations.
+#
+# Usage:
+# ./createIcuUpdateResources.sh <tzdata tar.gz file> <ICU version>
+#
+# e.g.
+# ./createIcuUpdateResources.sh ~/Downloads/tzdata2015b.tar.gz 55
+#
+# After execution the file is generated.
+
+if (( $# != 2 )); then
+ echo "Missing arguments"
+ echo "Usage:"
+ echo "./createIcuUpdateResources.sh <tzdata tar.gz file> <ICU version>"
+ exit 1
+fi
+
+if [[ -z "${ANDROID_BUILD_TOP}" ]]; then
+ echo "Configure your environment with build/envsetup.sh and lunch"
+ exit 1
+fi
+
+TZ_DATA_FILE=$1
+ICU_VERSION=$2
+
+if [[ ! -f ${TZ_DATA_FILE} ]]; then
+ echo "${TZ_DATA_FILE} not found"
+ exit 1
+fi
+
+# Keep track of the original working dir. Must be the "tools" dir.
+START_DIR=`pwd`
+ICU_DIR=${ANDROID_BUILD_TOP}/external/icu/icu4c/source
+BUILD_DIR=${START_DIR}/icu_build
+
+# Fail if anything below fails
+set -e
+
+rm -rf ${BUILD_DIR}
+mkdir -p ${BUILD_DIR}
+cd ${BUILD_DIR}
+
+# Configure the build
+${ICU_DIR}/runConfigureICU Linux
+mkdir -p ${BUILD_DIR}/bin
+cd ${BUILD_DIR}/tools/tzcode
+ln -s ${ICU_DIR}/tools/tzcode/icuregions ./icuregions
+ln -s ${ICU_DIR}/tools/tzcode/icuzones ./icuzones
+cp ${TZ_DATA_FILE} .
+
+# Make the tools
+make
+
+# Then make the whole thing
+cd ${BUILD_DIR}
+make -j32
+
+# Generate the tzdata.lst file used to configure which files are included.
+ICU_LIB_DIR=${BUILD_DIR}/lib
+BIN_DIR=${BUILD_DIR}/bin
+TZ_FILES=tzdata.lst
+
+echo metaZones.res > ${TZ_FILES}
+echo timezoneTypes.res >> ${TZ_FILES}
+echo windowsZones.res >> ${TZ_FILES}
+echo zoneinfo64.res >> ${TZ_FILES}
+
+# Copy all the .res files we need here a from, e.g. ./data/out/build/icudt55l
+RES_DIR=data/out/build/icudt${ICU_VERSION}l
+cp ${RES_DIR}/metaZones.res ${BUILD_DIR}
+cp ${RES_DIR}/timezoneTypes.res ${BUILD_DIR}
+cp ${RES_DIR}/windowsZones.res ${BUILD_DIR}
+cp ${RES_DIR}/zoneinfo64.res ${BUILD_DIR}
+
+# This is the package name required for the .dat file to be accepted by ICU.
+# This also affects the generated file name.
+ICU_PACKAGE=icudt${ICU_VERSION}l
+
+# Create the file
+LD_LIBRARY_PATH=${ICU_LIB_DIR} ${BIN_DIR}/pkgdata -F -m common -v -T . -d . -p ${ICU_PACKAGE} ${TZ_FILES}
+cp ${ICU_PACKAGE}.dat ${START_DIR}/icu_tzdata.dat
+
+# Copy the file to the original working dir.
+echo File can be found here: ${START_DIR}/icu_tzdata.dat
diff --git a/tzdata/tools/createTzDataBundle.sh b/tzdata/tools/createTzDataBundle.sh
new file mode 100755
index 0000000..05646fc
--- /dev/null
+++ b/tzdata/tools/createTzDataBundle.sh
@@ -0,0 +1,25 @@
+#!/bin/bash
+
+# A script to generate TZ data updates.
+#
+# Usage: ./createTzDataBundle.sh <tzupdate.properties file> <output file>
+# See libcore.tzdata.update.tools.CreateTzDataBundle for more information.
+
+TOOLS_DIR=src/main/libcore/tzdata/update/tools
+UPDATE_DIR=../update/src/main/libcore/tzdata/update
+GEN_DIR=./gen
+
+# Fail if anything below fails
+set -e
+
+rm -rf ${GEN_DIR}
+mkdir -p ${GEN_DIR}
+
+javac \
+ ${TOOLS_DIR}/CreateTzDataBundle.java \
+ ${TOOLS_DIR}/TzDataBundleBuilder.java \
+ ${UPDATE_DIR}/ConfigBundle.java \
+ ${UPDATE_DIR}/FileUtils.java \
+ -d ${GEN_DIR}
+
+java -cp ${GEN_DIR} libcore.tzdata.update.tools.CreateTzDataBundle $@
diff --git a/tzdata/tools/src/main/libcore/tzdata/update/tools/CreateTzDataBundle.java b/tzdata/tools/src/main/libcore/tzdata/update/tools/CreateTzDataBundle.java
new file mode 100644
index 0000000..cdb004a
--- /dev/null
+++ b/tzdata/tools/src/main/libcore/tzdata/update/tools/CreateTzDataBundle.java
@@ -0,0 +1,127 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package libcore.tzdata.update.tools;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.io.Reader;
+import java.util.Properties;
+import libcore.tzdata.update.ConfigBundle;
+import libcore.tzdata.update.FileUtils;
+
+/**
+ * A command-line tool for creating a TZ data update bundle.
+ *
+ * Args:
+ * tzdata.properties file - the file describing the bundle (see template file in tzdata/tools)
+ * output file - the name of the file to be generated
+ */
+public class CreateTzDataBundle {
+
+ private CreateTzDataBundle() {}
+
+ public static void main(String[] args) throws Exception {
+ if (args.length != 2) {
+ printUsage();
+ System.exit(1);
+ }
+ File f = new File(args[0]);
+ if (!f.exists()) {
+ System.err.println("Properties file " + f + " not found");
+ printUsage();
+ System.exit(2);
+ }
+ Properties p = loadProperties(f);
+ TzDataBundleBuilder builder = new TzDataBundleBuilder()
+ .setTzDataVersion(getMandatoryProperty(p, "tzdata.version"))
+ .addBionicTzData(getMandatoryPropertyFile(p, "bionic.file"))
+ .addIcuTzData(getMandatoryPropertyFile(p, "icu.file"));
+
+ int i = 1;
+ while (true) {
+ String localFileNameProperty = "checksum.file.local." + i;
+ String localFileName = p.getProperty(localFileNameProperty);
+ String onDeviceFileNameProperty = "checksum.file.ondevice." + i;
+ String onDeviceFileName = p.getProperty(onDeviceFileNameProperty);
+ boolean foundLocalFileNameProperty = localFileName != null;
+ boolean foundOnDeviceFileNameProperty = onDeviceFileName != null;
+ if (!foundLocalFileNameProperty && !foundOnDeviceFileNameProperty) {
+ break;
+ } else if (foundLocalFileNameProperty != foundOnDeviceFileNameProperty) {
+ System.out.println("Properties file must specify both, or neither of: "
+ + localFileNameProperty + " and " + onDeviceFileNameProperty);
+ System.exit(5);
+ }
+
+ long checksum = FileUtils.calculateChecksum(new File(localFileName));
+ builder.addChecksum(onDeviceFileName, checksum);
+ i++;
+ }
+ if (i == 1) {
+ // For safety we enforce >= 1 checksum entry. The installer does not require it.
+ System.out.println("There must be at least one checksum file");
+ System.exit(6);
+ }
+ System.out.println("Update contains checksums for " + (i-1) + " files");
+
+ ConfigBundle bundle = builder.build();
+ File outputFile = new File(args[1]);
+ try (OutputStream os = new FileOutputStream(outputFile)) {
+ os.write(bundle.getBundleBytes());
+ }
+ System.out.println("Wrote: " + outputFile);
+ }
+
+ private static File getMandatoryPropertyFile(Properties p, String propertyName) {
+ String fileName = getMandatoryProperty(p, propertyName);
+ File file = new File(fileName);
+ if (!file.exists()) {
+ System.out.println(
+ "Missing file: " + file + " for property " + propertyName + " does not exist.");
+ printUsage();
+ System.exit(4);
+ }
+ return file;
+ }
+
+ private static String getMandatoryProperty(Properties p, String propertyName) {
+ String value = p.getProperty(propertyName);
+ if (value == null) {
+ System.out.println("Missing property: " + propertyName);
+ printUsage();
+ System.exit(3);
+ }
+ return value;
+ }
+
+ private static Properties loadProperties(File f) throws IOException {
+ Properties p = new Properties();
+ try (Reader reader = new InputStreamReader(new FileInputStream(f))) {
+ p.load(reader);
+ }
+ return p;
+ }
+
+ private static void printUsage() {
+ System.out.println("Usage:");
+ System.out.println("\t" + CreateTzDataBundle.class.getName() +
+ " <tzupdate.properties file> <output file>");
+ }
+}
diff --git a/tzdata/tools/src/main/libcore/tzdata/update/tools/TzDataBundleBuilder.java b/tzdata/tools/src/main/libcore/tzdata/update/tools/TzDataBundleBuilder.java
new file mode 100644
index 0000000..3550c6f
--- /dev/null
+++ b/tzdata/tools/src/main/libcore/tzdata/update/tools/TzDataBundleBuilder.java
@@ -0,0 +1,134 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package libcore.tzdata.update.tools;
+
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipOutputStream;
+import libcore.tzdata.update.ConfigBundle;
+
+/**
+ * A class for creating a {@link ConfigBundle} containing timezone update data.
+ */
+public final class TzDataBundleBuilder {
+
+ private String tzDataVersion;
+ private StringBuilder checksumsFileContent = new StringBuilder();
+ private File zoneInfoFile;
+ private File icuTzDataFile;
+
+ public TzDataBundleBuilder setTzDataVersion(String tzDataVersion) {
+ this.tzDataVersion = tzDataVersion;
+ return this;
+ }
+
+ public TzDataBundleBuilder addChecksum(String fileName, long checksum) {
+ checksumsFileContent.append(Long.toString(checksum))
+ .append(',')
+ .append(fileName)
+ .append('\n');
+ return this;
+ }
+
+ public TzDataBundleBuilder addBionicTzData(File zoneInfoFile) {
+ this.zoneInfoFile = zoneInfoFile;
+ return this;
+ }
+
+ public TzDataBundleBuilder addIcuTzData(File icuTzDataFile) {
+ this.icuTzDataFile = icuTzDataFile;
+ return this;
+ }
+
+ /**
+ * Builds a {@link libcore.tzdata.update.ConfigBundle}.
+ */
+ public ConfigBundle build() throws IOException {
+ if (tzDataVersion == null) {
+ throw new IllegalStateException("Missing tzDataVersion");
+ }
+ if (zoneInfoFile == null) {
+ throw new IllegalStateException("Missing zoneInfo file");
+ }
+
+ return buildUnvalidated();
+ }
+
+ // For use in tests.
+ public TzDataBundleBuilder clearChecksumEntries() {
+ checksumsFileContent.setLength(0);
+ return this;
+ }
+
+ // For use in tests.
+ public TzDataBundleBuilder clearBionicTzData() {
+ this.zoneInfoFile = null;
+ return this;
+ }
+
+ /**
+ * For use in tests. Use {@link #build()}.
+ */
+ public ConfigBundle buildUnvalidated() throws IOException {
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ try (ZipOutputStream zos = new ZipOutputStream(baos)) {
+ addZipEntry(zos, ConfigBundle.CHECKSUMS_FILE_NAME,
+ checksumsFileContent.toString().getBytes(StandardCharsets.UTF_8));
+ if (tzDataVersion != null) {
+ addZipEntry(zos, ConfigBundle.TZ_DATA_VERSION_FILE_NAME,
+ tzDataVersion.getBytes(StandardCharsets.UTF_8));
+ }
+ if (zoneInfoFile != null) {
+ addZipEntry(zos, ConfigBundle.ZONEINFO_FILE_NAME,
+ readFileAsByteArray(zoneInfoFile));
+ }
+ if (icuTzDataFile != null) {
+ addZipEntry(zos, ConfigBundle.ICU_DATA_FILE_NAME,
+ readFileAsByteArray(icuTzDataFile));
+ }
+ }
+ return new ConfigBundle(baos.toByteArray());
+ }
+
+ private static void addZipEntry(ZipOutputStream zos, String name, byte[] content)
+ throws IOException {
+ ZipEntry zipEntry = new ZipEntry(name);
+ zipEntry.setSize(content.length);
+ zos.putNextEntry(zipEntry);
+ zos.write(content);
+ zos.closeEntry();
+ }
+
+ /**
+ * Returns the contents of 'path' as a byte array.
+ */
+ public static byte[] readFileAsByteArray(File file) throws IOException {
+ byte[] buffer = new byte[8192];
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ try (FileInputStream fis = new FileInputStream(file)) {
+ int count;
+ while ((count = fis.read(buffer)) != -1) {
+ baos.write(buffer, 0, count);
+ }
+ }
+ return baos.toByteArray();
+ }
+}
+
diff --git a/tzdata/tools/tzupdate.properties b/tzdata/tools/tzupdate.properties
new file mode 100644
index 0000000..e3fe002
--- /dev/null
+++ b/tzdata/tools/tzupdate.properties
@@ -0,0 +1,14 @@
+# Edit these to reflect the update files.
+
+# This should be the tzdata version. e.g. "2015a". Lexicographical sort order
+# may become important in future so if inventing interim releases only add
+# characters to the end.
+tzdata.version=
+bionic.file=
+icu.file=
+
+# Edit these as required to point to the file expected to exist on the device.
+checksum.file.local.1=../../../bionic/libc/zoneinfo/tzdata
+checksum.file.ondevice.1=/system/usr/share/zoneinfo/tzdata
+checksum.file.local.2=../../../external/icu/icu4c/source/stubdata/icudt55l.dat
+checksum.file.ondevice.2=/system/usr/icu/icudt55l.dat
diff --git a/tzdata/update/src/main/libcore/tzdata/update/ConfigBundle.java b/tzdata/update/src/main/libcore/tzdata/update/ConfigBundle.java
new file mode 100644
index 0000000..b497c85
--- /dev/null
+++ b/tzdata/update/src/main/libcore/tzdata/update/ConfigBundle.java
@@ -0,0 +1,123 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package libcore.tzdata.update;
+
+import java.io.ByteArrayInputStream;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Arrays;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipInputStream;
+
+/**
+ * A configuration bundle. This is a thin wrapper around some in-memory bytes representing a zip
+ * archive and logic for its safe extraction.
+ */
+public final class ConfigBundle {
+
+ /** The name of the file inside the bundle containing the TZ data version. */
+ public static final String TZ_DATA_VERSION_FILE_NAME = "tzdata_version";
+
+ /** The name of the file inside the bundle containing the expected device checksums. */
+ public static final String CHECKSUMS_FILE_NAME = "checksums";
+
+ /** The name of the file inside the bundle containing bionic/libcore TZ data. */
+ public static final String ZONEINFO_FILE_NAME = "tzdata";
+
+ /** The name of the file inside the bundle containing ICU TZ data. */
+ public static final String ICU_DATA_FILE_NAME = "icu/icu_tzdata.dat";
+
+ private static final int BUFFER_SIZE = 8192;
+
+ private final byte[] bytes;
+
+ public ConfigBundle(byte[] bytes) {
+ this.bytes = bytes;
+ }
+
+ public byte[] getBundleBytes() {
+ return bytes;
+ }
+
+ public void extractTo(File targetDir) throws IOException {
+ extractZipSafely(new ByteArrayInputStream(bytes), targetDir, true /* makeWorldReadable */);
+ }
+
+ /** Visible for testing */
+ static void extractZipSafely(InputStream is, File targetDir, boolean makeWorldReadable)
+ throws IOException {
+
+ // Create the extraction dir, if needed.
+ FileUtils.ensureDirectoriesExist(targetDir, makeWorldReadable);
+
+ try (ZipInputStream zipInputStream = new ZipInputStream(is)) {
+ byte[] buffer = new byte[BUFFER_SIZE];
+ ZipEntry entry;
+ while ((entry = zipInputStream.getNextEntry()) != null) {
+ // Validate the entry name: make sure the unpacked file will exist beneath the
+ // targetDir.
+ String name = entry.getName();
+ // Note, we assume that nothing will quickly insert a symlink after createSubFile()
+ // that might invalidate the guarantees about name existing beneath targetDir.
+ File entryFile = FileUtils.createSubFile(targetDir, name);
+
+ if (entry.isDirectory()) {
+ FileUtils.ensureDirectoriesExist(entryFile, makeWorldReadable);
+ } else {
+ // Create the path if there was no directory entry.
+ if (!entryFile.getParentFile().exists()) {
+ FileUtils.ensureDirectoriesExist(
+ entryFile.getParentFile(), makeWorldReadable);
+ }
+
+ try (FileOutputStream fos = new FileOutputStream(entryFile)) {
+ int count;
+ while ((count = zipInputStream.read(buffer)) != -1) {
+ fos.write(buffer, 0, count);
+ }
+ // sync to disk
+ fos.getFD().sync();
+ }
+ // mark entryFile -rw-r--r--
+ if (makeWorldReadable) {
+ FileUtils.makeWorldReadable(entryFile);
+ }
+ }
+ }
+ }
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+
+ ConfigBundle that = (ConfigBundle) o;
+
+ if (!Arrays.equals(bytes, that.bytes)) {
+ return false;
+ }
+
+ return true;
+ }
+
+}
diff --git a/tzdata/update/src/main/libcore/tzdata/update/FileUtils.java b/tzdata/update/src/main/libcore/tzdata/update/FileUtils.java
new file mode 100644
index 0000000..652b786
--- /dev/null
+++ b/tzdata/update/src/main/libcore/tzdata/update/FileUtils.java
@@ -0,0 +1,197 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package libcore.tzdata.update;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.zip.CRC32;
+
+/**
+ * Utility methods for files operations.
+ */
+public final class FileUtils {
+
+ private FileUtils() {
+ }
+
+ /**
+ * Creates a new {@link java.io.File} from the {@code parentDir} and {@code name}, but only if
+ * the resulting file would exist beneath {@code parentDir}. Useful if {@code name} could
+ * contain "/../" or symlinks. The returned object has a canonicalized path.
+ *
+ * @throws java.io.IOException if the file would not exist beneath {@code parentDir}
+ */
+ public static File createSubFile(File parentDir, String name) throws IOException {
+ // The subFile must exist beneath parentDir. If name contains "/../" this may not be the
+ // case so we check.
+ File subFile = new File(parentDir, name).getCanonicalFile();
+ if (!subFile.getPath().startsWith(parentDir.getCanonicalPath())) {
+ throw new IOException(name + " must exist beneath " + parentDir +
+ ". Canonicalized subpath: " + subFile);
+ }
+ return subFile;
+ }
+
+ /**
+ * Makes sure a directory exists. If it doesn't exist, it is created. Parent directories are
+ * also created as needed. If {@code makeWorldReadable} is {@code true} the directory's default
+ * permissions will be set. Even when {@code makeWorldReadable} is {@code true}, only
+ * directories explicitly created will have their permissions set; existing directories are
+ * untouched.
+ *
+ * @throws IOException if the directory or one of its parents did not already exist and could
+ * not be created
+ */
+ public static void ensureDirectoriesExist(File dir, boolean makeWorldReadable)
+ throws IOException {
+ LinkedList<File> dirs = new LinkedList<>();
+ File currentDir = dir;
+ do {
+ dirs.addFirst(currentDir);
+ currentDir = currentDir.getParentFile();
+ } while (currentDir != null);
+
+ for (File dirToCheck : dirs) {
+ if (!dirToCheck.exists()) {
+ if (!dirToCheck.mkdir()) {
+ throw new IOException("Unable to create directory: " + dir);
+ }
+ if (makeWorldReadable) {
+ makeDirectoryWorldAccessible(dirToCheck);
+ }
+ } else if (!dirToCheck.isDirectory()) {
+ throw new IOException(dirToCheck + " exists but is not a directory");
+ }
+ }
+ }
+
+ public static void makeDirectoryWorldAccessible(File directory) throws IOException {
+ if (!directory.isDirectory()) {
+ throw new IOException(directory + " must be a directory");
+ }
+ makeWorldReadable(directory);
+ if (!directory.setExecutable(true, false /* ownerOnly */)) {
+ throw new IOException("Unable to make " + directory + " world-executable");
+ }
+ }
+
+ public static void makeWorldReadable(File file) throws IOException {
+ if (!file.setReadable(true, false /* ownerOnly */)) {
+ throw new IOException("Unable to make " + file + " world-readable");
+ }
+ }
+
+ /**
+ * Calculates the checksum from the contents of a file.
+ */
+ public static long calculateChecksum(File file) throws IOException {
+ final int BUFFER_SIZE = 8196;
+ CRC32 crc32 = new CRC32();
+ try (FileInputStream fis = new FileInputStream(file)) {
+ byte[] buffer = new byte[BUFFER_SIZE];
+ int count;
+ while ((count = fis.read(buffer)) != -1) {
+ crc32.update(buffer, 0, count);
+ }
+ }
+ return crc32.getValue();
+ }
+
+ public static void rename(File from, File to) throws IOException {
+ ensureFileDoesNotExist(to);
+ if (!from.renameTo(to)) {
+ throw new IOException("Unable to rename " + from + " to " + to);
+ }
+ }
+
+ public static void ensureFileDoesNotExist(File file) throws IOException {
+ if (file.exists()) {
+ if (!file.isFile()) {
+ throw new IOException(file + " is not a file");
+ }
+ doDelete(file);
+ }
+ }
+
+ public static void doDelete(File file) throws IOException {
+ if (!file.delete()) {
+ throw new IOException("Unable to delete: " + file);
+ }
+ }
+
+ public static boolean isSymlink(File file) throws IOException {
+ String baseName = file.getName();
+ String canonicalPathExceptBaseName =
+ new File(file.getParentFile().getCanonicalFile(), baseName).getPath();
+ return !file.getCanonicalPath().equals(canonicalPathExceptBaseName);
+ }
+
+ public static void deleteRecursive(File toDelete) throws IOException {
+ if (toDelete.isDirectory()) {
+ for (File file : toDelete.listFiles()) {
+ if (file.isDirectory() && !FileUtils.isSymlink(file)) {
+ // The isSymlink() check is important so that we don't delete files in other
+ // directories: only the symlink itself.
+ deleteRecursive(file);
+ } else {
+ // Delete symlinks to directories or files.
+ FileUtils.doDelete(file);
+ }
+ }
+ String[] remainingFiles = toDelete.list();
+ if (remainingFiles.length != 0) {
+ throw new IOException("Unable to delete files: " + Arrays
+ .toString(remainingFiles));
+ }
+ }
+ FileUtils.doDelete(toDelete);
+ }
+
+ public static boolean filesExist(File rootDir, String... fileNames) throws IOException {
+ for (String fileName : fileNames) {
+ File file = new File(rootDir, fileName);
+ if (!file.exists()) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Read all lines from a UTF-8 encoded file, returning them as a list of strings.
+ */
+ public static List<String> readLines(File file) throws IOException {
+ FileInputStream in = new FileInputStream(file);
+ try (BufferedReader fileReader = new BufferedReader(
+ new InputStreamReader(in, StandardCharsets.UTF_8));
+ ) {
+ List<String> lines = new ArrayList<>();
+ String line;
+ while ((line = fileReader.readLine()) != null) {
+ lines.add(line);
+ }
+ return lines;
+ }
+ }
+}
diff --git a/tzdata/update/src/main/libcore/tzdata/update/TzDataBundleInstaller.java b/tzdata/update/src/main/libcore/tzdata/update/TzDataBundleInstaller.java
new file mode 100644
index 0000000..df0b2a7
--- /dev/null
+++ b/tzdata/update/src/main/libcore/tzdata/update/TzDataBundleInstaller.java
@@ -0,0 +1,141 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package libcore.tzdata.update;
+
+import android.util.Slog;
+
+import java.io.File;
+import java.io.IOException;
+
+/**
+ * A bundle-validation / extraction class. Separate from the services code that uses it for easier
+ * testing.
+ */
+public final class TzDataBundleInstaller {
+
+ static final String CURRENT_TZ_DATA_DIR_NAME = "current";
+ static final String WORKING_DIR_NAME = "working";
+ static final String OLD_TZ_DATA_DIR_NAME = "old";
+
+ private final String logTag;
+ private final File installDir;
+
+ public TzDataBundleInstaller(String logTag, File installDir) {
+ this.logTag = logTag;
+ this.installDir = installDir;
+ }
+
+ /**
+ * Install the supplied content.
+ *
+ * <p>Errors during unpacking or installation will throw an {@link IOException}.
+ * If the content is invalid this method returns {@code false}.
+ * If the installation completed successfully this method returns {@code true}.
+ */
+ public boolean install(byte[] content) throws IOException {
+ File oldTzDataDir = new File(installDir, OLD_TZ_DATA_DIR_NAME);
+ if (oldTzDataDir.exists()) {
+ FileUtils.deleteRecursive(oldTzDataDir);
+ }
+
+ File currentTzDataDir = new File(installDir, CURRENT_TZ_DATA_DIR_NAME);
+ File workingDir = new File(installDir, WORKING_DIR_NAME);
+
+ Slog.i(logTag, "Applying time zone update");
+ File unpackedContentDir = unpackBundle(content, workingDir);
+ try {
+ if (!checkBundleFilesExist(unpackedContentDir)) {
+ Slog.i(logTag, "Update not applied: Bundle is missing files");
+ return false;
+ }
+
+ if (verifySystemChecksums(unpackedContentDir)) {
+ FileUtils.makeDirectoryWorldAccessible(unpackedContentDir);
+
+ if (currentTzDataDir.exists()) {
+ Slog.i(logTag, "Moving " + currentTzDataDir + " to " + oldTzDataDir);
+ FileUtils.rename(currentTzDataDir, oldTzDataDir);
+ }
+ Slog.i(logTag, "Moving " + unpackedContentDir + " to " + currentTzDataDir);
+ FileUtils.rename(unpackedContentDir, currentTzDataDir);
+ Slog.i(logTag, "Update applied: " + currentTzDataDir + " successfully created");
+ return true;
+ }
+ Slog.i(logTag, "Update not applied: System checksum did not match");
+ return false;
+ } finally {
+ deleteBestEffort(oldTzDataDir);
+ deleteBestEffort(unpackedContentDir);
+ }
+ }
+
+ private void deleteBestEffort(File dir) {
+ if (dir.exists()) {
+ try {
+ FileUtils.deleteRecursive(dir);
+ } catch (IOException e) {
+ // Logged but otherwise ignored.
+ Slog.w(logTag, "Unable to delete " + dir, e);
+ }
+ }
+ }
+
+ private File unpackBundle(byte[] content, File targetDir) throws IOException {
+ Slog.i(logTag, "Unpacking update content to: " + targetDir);
+ ConfigBundle bundle = new ConfigBundle(content);
+ bundle.extractTo(targetDir);
+ return targetDir;
+ }
+
+ private boolean checkBundleFilesExist(File unpackedContentDir) throws IOException {
+ Slog.i(logTag, "Verifying bundle contents");
+ return FileUtils.filesExist(unpackedContentDir,
+ ConfigBundle.TZ_DATA_VERSION_FILE_NAME,
+ ConfigBundle.CHECKSUMS_FILE_NAME,
+ ConfigBundle.ZONEINFO_FILE_NAME,
+ ConfigBundle.ICU_DATA_FILE_NAME);
+ }
+
+ private boolean verifySystemChecksums(File unpackedContentDir) throws IOException {
+ Slog.i(logTag, "Verifying system file checksums");
+ File checksumsFile = new File(unpackedContentDir, ConfigBundle.CHECKSUMS_FILE_NAME);
+ for (String line : FileUtils.readLines(checksumsFile)) {
+ int delimiterPos = line.indexOf(',');
+ if (delimiterPos <= 0 || delimiterPos == line.length() - 1) {
+ throw new IOException("Bad checksum entry: " + line);
+ }
+ long expectedChecksum;
+ try {
+ expectedChecksum = Long.parseLong(line.substring(0, delimiterPos));
+ } catch (NumberFormatException e) {
+ throw new IOException("Invalid checksum value: " + line);
+ }
+ String filePath = line.substring(delimiterPos + 1);
+ File file = new File(filePath);
+ if (!file.exists()) {
+ Slog.i(logTag, "Failed checksum test for file: " + file + ": file not found");
+ return false;
+ }
+ long actualChecksum = FileUtils.calculateChecksum(file);
+ if (actualChecksum != expectedChecksum) {
+ Slog.i(logTag, "Failed checksum test for file: " + file
+ + ": required=" + expectedChecksum + ", actual=" + actualChecksum);
+ return false;
+ }
+ }
+ return true;
+ }
+}
diff --git a/tzdata/update/src/test/libcore/tzdata/update/ConfigBundleTest.java b/tzdata/update/src/test/libcore/tzdata/update/ConfigBundleTest.java
new file mode 100644
index 0000000..f1325e7
--- /dev/null
+++ b/tzdata/update/src/test/libcore/tzdata/update/ConfigBundleTest.java
@@ -0,0 +1,151 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package libcore.tzdata.update;
+
+import junit.framework.TestCase;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FilterInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipOutputStream;
+import libcore.io.IoUtils;
+
+/**
+ * Tests for {@link ConfigBundle}.
+ */
+public class ConfigBundleTest extends TestCase {
+
+ private final List<File> testFiles = new ArrayList<>();
+
+ @Override
+ public void tearDown() throws Exception {
+ // Delete files / directories in reverse order.
+ Collections.reverse(testFiles);
+ for (File tempFile : testFiles) {
+ tempFile.delete();
+ }
+ super.tearDown();
+ }
+
+ public void testExtractZipSafely_goodZip() throws Exception {
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ try (ZipOutputStream zipOutputStream = new ZipOutputStream(baos)) {
+ addZipEntry(zipOutputStream, "/leadingSlash");
+ addZipEntry(zipOutputStream, "absolute");
+ addZipEntry(zipOutputStream, "subDir/../file");
+ addZipEntry(zipOutputStream, "subDir/subDir/subDir/file");
+ addZipEntry(zipOutputStream, "subDir/subDir2/"); // Directory entry
+ addZipEntry(zipOutputStream, "subDir/../subDir3/"); // Directory entry
+ }
+ File dir = createTempDir();
+ File targetDir = new File(dir, "target");
+ TestInputStream inputStream =
+ new TestInputStream(new ByteArrayInputStream(baos.toByteArray()));
+ ConfigBundle.extractZipSafely(inputStream, targetDir, true /* makeWorldReadable */);
+ inputStream.assertClosed();
+ assertFilesExist(
+ new File(targetDir, "leadingSlash"),
+ new File(targetDir, "absolute"),
+ new File(targetDir, "file"),
+ new File(targetDir, "subDir/subDir/subDir/file"));
+ assertDirsExist(
+ new File(targetDir, "subDir/subDir2"),
+ new File(targetDir, "subDir3"));
+ }
+
+ public void testExtractZipSafely_badZip_fileOutsideTarget() throws Exception {
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ try (ZipOutputStream zipOutputStream = new ZipOutputStream(baos)) {
+ addZipEntry(zipOutputStream, "../one");
+ }
+ doExtractZipFails(baos);
+ }
+
+ public void testExtractZipSafely_badZip_dirOutsideTarget() throws Exception {
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ try (ZipOutputStream zipOutputStream = new ZipOutputStream(baos)) {
+ addZipEntry(zipOutputStream, "../one/");
+ }
+ doExtractZipFails(baos);
+ }
+
+ private void doExtractZipFails(ByteArrayOutputStream baos) {
+ File dir = createTempDir();
+ File targetDir = new File(dir, "target");
+ TestInputStream inputStream = new TestInputStream(
+ new ByteArrayInputStream(baos.toByteArray()));
+ try {
+ ConfigBundle.extractZipSafely(inputStream, targetDir, true /* makeWorldReadable */);
+ fail();
+ } catch (IOException expected) {
+ }
+ inputStream.assertClosed();
+ }
+
+ private static void addZipEntry(ZipOutputStream zipOutputStream, String name)
+ throws IOException {
+ ZipEntry zipEntry = new ZipEntry(name);
+ zipOutputStream.putNextEntry(zipEntry);
+ if (!zipEntry.isDirectory()) {
+ zipOutputStream.write('a');
+ }
+ }
+
+ private File createTempDir() {
+ final String tempPrefix = getClass().getSimpleName();
+ File tempDir = IoUtils.createTemporaryDirectory(tempPrefix);
+ testFiles.add(tempDir);
+ return tempDir;
+ }
+
+ private static void assertFilesExist(File... files) {
+ for (File f : files) {
+ assertTrue(f + " file expected to exist", f.exists() && f.isFile());
+ }
+ }
+
+ private static void assertDirsExist(File... dirs) {
+ for (File dir : dirs) {
+ assertTrue(dir + " directory expected to exist", dir.exists() && dir.isDirectory());
+ }
+ }
+
+ private static class TestInputStream extends FilterInputStream {
+
+ private boolean closed;
+
+ public TestInputStream(InputStream in) {
+ super(in);
+ }
+
+ @Override
+ public void close() throws IOException {
+ closed = true;
+ super.close();
+ }
+
+ public void assertClosed() {
+ assertTrue(closed);
+ }
+ }
+}
diff --git a/tzdata/update/src/test/libcore/tzdata/update/FileUtilsTest.java b/tzdata/update/src/test/libcore/tzdata/update/FileUtilsTest.java
new file mode 100644
index 0000000..d002820
--- /dev/null
+++ b/tzdata/update/src/test/libcore/tzdata/update/FileUtilsTest.java
@@ -0,0 +1,329 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package libcore.tzdata.update;
+
+import junit.framework.TestCase;
+
+import android.system.Os;
+import android.system.OsConstants;
+import android.system.StructStat;
+
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStreamWriter;
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import libcore.io.IoUtils;
+import libcore.io.Libcore;
+
+/**
+ * Tests for {@link FileUtils}.
+ */
+public class FileUtilsTest extends TestCase {
+
+ private List<File> testFiles = new ArrayList<>();
+
+ @Override
+ public void tearDown() throws Exception {
+ // Delete in reverse order
+ Collections.reverse(testFiles);
+ for (File tempFile : testFiles) {
+ tempFile.delete();
+ }
+ super.tearDown();
+ }
+
+ public void testCalculateChecksum() throws Exception {
+ final String content = "Content";
+ File file1 = createTextFile(content);
+ File file2 = createTextFile(content);
+ File file3 = createTextFile(content + "!");
+
+ long file1CheckSum = FileUtils.calculateChecksum(file1);
+ long file2CheckSum = FileUtils.calculateChecksum(file2);
+ long file3Checksum = FileUtils.calculateChecksum(file3);
+
+ assertEquals(file1CheckSum, file2CheckSum);
+ assertTrue(file1CheckSum != file3Checksum);
+ }
+
+ public void testDeleteRecursive() throws Exception {
+ File dir = createTempDir();
+ File file1 = createRegularFile(dir, "file1");
+ File file2 = createRegularFile(dir, "file2");
+ File symLink1 = createSymlink(file1, dir, "symLink1");
+ File subDir = createDir(dir, "subDir");
+ File file3 = createRegularFile(subDir, "subFile1");
+ File file4 = createRegularFile(subDir, "subFile2");
+ File symLink2 = createSymlink(file1, dir, "symLink2");
+
+ File otherDir = createTempDir();
+ File otherFile = createRegularFile(otherDir, "kept");
+
+ File linkToOtherDir = createSymlink(otherDir, subDir, "linkToOtherDir");
+ File linkToOtherFile = createSymlink(otherFile, subDir, "linkToOtherFile");
+
+ File[] filesToDelete = { dir, file1, file2, symLink1, subDir, file3, file4, symLink2,
+ linkToOtherDir, linkToOtherFile };
+ File[] filesToKeep = { otherDir, otherFile };
+ assertFilesExist(filesToDelete);
+ assertFilesExist(filesToKeep);
+
+ FileUtils.deleteRecursive(dir);
+ assertFilesDoNotExist(filesToDelete);
+ assertFilesExist(filesToKeep);
+ }
+
+ public void testIsSymlink() throws Exception {
+ File dir = createTempDir();
+ File subDir = createDir(dir, "subDir");
+ File fileInSubDir = createRegularFile(subDir, "fileInSubDir");
+ File normalFile = createRegularFile(dir, "normalFile");
+ File symlinkToDir = createSymlink(subDir, dir, "symlinkToDir");
+ File symlinkToFile = createSymlink(fileInSubDir, dir, "symlinkToFile");
+ File symlinkToFileInSubDir = createSymlink(fileInSubDir, dir, "symlinkToFileInSubDir");
+ File normalFileViaSymlink = new File(symlinkToDir, "normalFile");
+
+ assertFalse(FileUtils.isSymlink(dir));
+ assertFalse(FileUtils.isSymlink(subDir));
+ assertFalse(FileUtils.isSymlink(fileInSubDir));
+ assertFalse(FileUtils.isSymlink(normalFile));
+ assertTrue(FileUtils.isSymlink(symlinkToDir));
+ assertTrue(FileUtils.isSymlink(symlinkToFile));
+ assertTrue(FileUtils.isSymlink(symlinkToFileInSubDir));
+ assertFalse(FileUtils.isSymlink(normalFileViaSymlink));
+ }
+
+ public void testCreateSubFile() throws Exception {
+ File dir1 = createTempDir().getCanonicalFile();
+
+ File actualSubFile = FileUtils.createSubFile(dir1, "file");
+ assertEquals(new File(dir1, "file"), actualSubFile);
+
+ File existingSubFile = createRegularFile(dir1, "file");
+ actualSubFile = FileUtils.createSubFile(dir1, "file");
+ assertEquals(existingSubFile, actualSubFile);
+
+ File existingSubDir = createDir(dir1, "subdir");
+ actualSubFile = FileUtils.createSubFile(dir1, "subdir");
+ assertEquals(existingSubDir, actualSubFile);
+
+ assertCreateSubFileThrows(dir1, "../file");
+ assertCreateSubFileThrows(dir1, "../../file");
+ assertCreateSubFileThrows(dir1, "../otherdir/file");
+
+ File dir2 = createTempDir().getCanonicalFile();
+ createSymlink(dir2, dir1, "symlinkToDir2");
+ assertCreateSubFileThrows(dir1, "symlinkToDir2");
+
+ assertCreateSubFileThrows(dir1, "symlinkToDir2/fileInSymlinkedDir");
+
+ createRegularFile(dir1, "symlinkToDir2/fileInSymlinkedDir");
+ assertCreateSubFileThrows(dir1, "symlinkToDir2/fileInSymlinkedDir");
+ }
+
+ public void testEnsureDirectoryExists() throws Exception {
+ File dir = createTempDir();
+
+ File exists = new File(dir, "exists");
+ assertTrue(exists.mkdir());
+ assertTrue(exists.setReadable(true /* readable */, true /* ownerOnly */));
+ assertTrue(exists.setExecutable(true /* readable */, true /* ownerOnly */));
+ FileUtils.ensureDirectoriesExist(exists, true /* makeWorldReadable */);
+ assertDirExistsAndIsAccessible(exists, false /* requireWorldReadable */);
+
+ File subDir = new File(dir, "subDir");
+ assertFalse(subDir.exists());
+ FileUtils.ensureDirectoriesExist(subDir, true /* makeWorldReadable */);
+ assertDirExistsAndIsAccessible(subDir, true /* requireWorldReadable */);
+
+ File one = new File(dir, "one");
+ File two = new File(one, "two");
+ File three = new File(two, "three");
+ FileUtils.ensureDirectoriesExist(three, true /* makeWorldReadable */);
+ assertDirExistsAndIsAccessible(one, true /* requireWorldReadable */);
+ assertDirExistsAndIsAccessible(two, true /* requireWorldReadable */);
+ assertDirExistsAndIsAccessible(three, true /* requireWorldReadable */);
+ }
+
+ public void testEnsureDirectoriesExist_noPermissions() throws Exception {
+ File dir = createTempDir();
+ assertDirExistsAndIsAccessible(dir, false /* requireWorldReadable */);
+
+ File unreadableSubDir = new File(dir, "unreadableSubDir");
+ assertTrue(unreadableSubDir.mkdir());
+ assertTrue(unreadableSubDir.setReadable(false /* readable */, true /* ownerOnly */));
+ assertTrue(unreadableSubDir.setExecutable(false /* readable */, true /* ownerOnly */));
+
+ File toCreate = new File(unreadableSubDir, "toCreate");
+ try {
+ FileUtils.ensureDirectoriesExist(toCreate, true /* makeWorldReadable */);
+ fail();
+ } catch (IOException expected) {
+ }
+ assertDirExistsAndIsAccessible(dir, false /* requireWorldReadable */);
+ assertFalse(unreadableSubDir.canRead() && unreadableSubDir.canExecute());
+ assertFalse(toCreate.exists());
+ }
+
+ public void testEnsureFileDoesNotExist() throws Exception {
+ File dir = createTempDir();
+
+ FileUtils.ensureFileDoesNotExist(new File(dir, "doesNotExist"));
+
+ File exists1 = createRegularFile(dir, "exists1");
+ assertTrue(exists1.exists());
+ FileUtils.ensureFileDoesNotExist(exists1);
+ assertFalse(exists1.exists());
+
+ exists1 = createRegularFile(dir, "exists1");
+ File symlink = createSymlink(exists1, dir, "symlinkToFile");
+ assertTrue(symlink.exists());
+ FileUtils.ensureFileDoesNotExist(symlink);
+ assertFalse(symlink.exists());
+ assertTrue(exists1.exists());
+
+ // Only files and symlinks supported. We do not delete directories.
+ File emptyDir = createTempDir();
+ try {
+ FileUtils.ensureFileDoesNotExist(emptyDir);
+ fail();
+ } catch (IOException expected) {
+ }
+ assertTrue(emptyDir.exists());
+ }
+
+ // This test does not pass when run as root because root can do anything even if the permissions
+ // don't allow it.
+ public void testEnsureFileDoesNotExist_noPermission() throws Exception {
+ File dir = createTempDir();
+
+ File protectedDir = createDir(dir, "protected");
+ File undeletable = createRegularFile(protectedDir, "undeletable");
+ assertTrue(protectedDir.setWritable(false));
+ assertTrue(undeletable.exists());
+ try {
+ FileUtils.ensureFileDoesNotExist(undeletable);
+ fail();
+ } catch (IOException expected) {
+ } finally {
+ assertTrue(protectedDir.setWritable(true)); // Reset for clean-up
+ }
+ assertTrue(undeletable.exists());
+ }
+
+ public void testCheckFilesExist() throws Exception {
+ File dir = createTempDir();
+ createRegularFile(dir, "exists1");
+ File subDir = createDir(dir, "subDir");
+ createRegularFile(subDir, "exists2");
+ assertTrue(FileUtils.filesExist(dir, "exists1", "subDir/exists2"));
+ assertFalse(FileUtils.filesExist(dir, "doesNotExist"));
+ assertFalse(FileUtils.filesExist(dir, "subDir/doesNotExist"));
+ }
+
+ public void testReadLines() throws Exception {
+ File file = createTextFile("One\nTwo\nThree\n");
+
+ List<String> lines = FileUtils.readLines(file);
+ assertEquals(3, lines.size());
+ assertEquals(lines, Arrays.asList("One", "Two", "Three"));
+ }
+
+ private File createTextFile(String contents) throws IOException {
+ File file = File.createTempFile(getClass().getSimpleName(), ".txt");
+ try (FileOutputStream fos = new FileOutputStream(file)) {
+ BufferedWriter writer = new BufferedWriter(
+ new OutputStreamWriter(fos, StandardCharsets.UTF_8));
+ writer.write(contents);
+ writer.close();
+ }
+ return file;
+ }
+
+ private File createSymlink(File file, File symlinkDir, String symlinkName) throws Exception {
+ assertTrue(file.exists());
+
+ File symlink = new File(symlinkDir, symlinkName);
+ Os.symlink(file.getAbsolutePath(), symlink.getAbsolutePath());
+ testFiles.add(symlink);
+ return symlink;
+ }
+
+ private static void assertCreateSubFileThrows(File parentDir, String name) {
+ try {
+ FileUtils.createSubFile(parentDir, name);
+ fail();
+ } catch (IOException expected) {
+ assertTrue(expected.getMessage().contains("must exist beneath"));
+ }
+ }
+
+ private static void assertFilesDoNotExist(File... files) {
+ for (File f : files) {
+ assertFalse(f + " unexpectedly exists", f.exists());
+ }
+ }
+
+ private static void assertFilesExist(File... files) {
+ for (File f : files) {
+ assertTrue(f + " expected to exist", f.exists());
+ }
+ }
+
+ private static void assertDirExistsAndIsAccessible(File dir, boolean requireWorldReadable)
+ throws Exception {
+ assertTrue(dir.exists() && dir.isDirectory() && dir.canRead() && dir.canExecute());
+
+ String path = dir.getCanonicalPath();
+ StructStat sb = Libcore.os.stat(path);
+ int mask = OsConstants.S_IXUSR | OsConstants.S_IRUSR;
+ if (requireWorldReadable) {
+ mask = mask | OsConstants.S_IXGRP | OsConstants.S_IRGRP
+ | OsConstants.S_IXOTH | OsConstants.S_IROTH;
+ }
+ assertTrue("Permission mask required: " + Integer.toOctalString(mask),
+ (sb.st_mode & mask) == mask);
+ }
+
+ private File createTempDir() {
+ final String tempPrefix = getClass().getSimpleName();
+ File tempDir = IoUtils.createTemporaryDirectory(tempPrefix);
+ testFiles.add(tempDir);
+ return tempDir;
+ }
+
+ private File createDir(File parentDir, String name) {
+ File dir = new File(parentDir, name);
+ assertTrue(dir.mkdir());
+ testFiles.add(dir);
+ return dir;
+ }
+
+ private File createRegularFile(File dir, String name) throws Exception {
+ File file = new File(dir, name);
+ try (FileOutputStream fos = new FileOutputStream(file)) {
+ fos.write("Hello".getBytes());
+ }
+ testFiles.add(file);
+ return file;
+ }
+}
diff --git a/tzdata/update/src/test/libcore/tzdata/update/TzDataBundleInstallerTest.java b/tzdata/update/src/test/libcore/tzdata/update/TzDataBundleInstallerTest.java
new file mode 100644
index 0000000..1825bb3
--- /dev/null
+++ b/tzdata/update/src/test/libcore/tzdata/update/TzDataBundleInstallerTest.java
@@ -0,0 +1,210 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package libcore.tzdata.update;
+
+import junit.framework.TestCase;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import libcore.tzdata.update.tools.TzDataBundleBuilder;
+
+/**
+ * Tests for {@link libcore.tzdata.update.TzDataBundleInstaller}.
+ */
+public class TzDataBundleInstallerTest extends TestCase {
+
+ private static final File SYSTEM_ZONE_INFO_FILE = new File("/system/usr/share/zoneinfo/tzdata");
+
+ private TzDataBundleInstaller installer;
+ private File tempDir;
+ private File testInstallDir;
+
+ @Override
+ public void setUp() throws Exception {
+ super.setUp();
+ tempDir = createDirectory("tempDir");
+ testInstallDir = createDirectory("testInstall");
+ installer = new TzDataBundleInstaller("TzDataBundleInstallerTest", testInstallDir);
+ }
+
+ private static File createDirectory(String prefix) throws IOException {
+ File dir = File.createTempFile(prefix, "");
+ assertTrue(dir.delete());
+ assertTrue(dir.mkdir());
+ return dir;
+ }
+
+ @Override
+ public void tearDown() throws Exception {
+ if (testInstallDir.exists()) {
+ FileUtils.deleteRecursive(testInstallDir);
+ }
+ if (tempDir.exists()) {
+ FileUtils.deleteRecursive(tempDir);
+ }
+ super.tearDown();
+ }
+
+ /** Tests the first update on a device */
+ public void testSuccessfulFirstUpdate() throws Exception {
+ ConfigBundle tzData = createValidTzDataBundle("2030a");
+
+ assertTrue(install(tzData));
+ assertTzDataInstalled(tzData);
+ }
+
+ /**
+ * Tests an update on a device when there is a prior update already applied.
+ */
+ public void testSuccessfulFollowOnUpdate() throws Exception {
+ ConfigBundle tzData1 = createValidTzDataBundle("2030a");
+ assertTrue(install(tzData1));
+ assertTzDataInstalled(tzData1);
+
+ ConfigBundle tzData2 = createValidTzDataBundle("2030b");
+ assertTrue(install(tzData2));
+ assertTzDataInstalled(tzData2);
+ }
+
+
+ /** Tests that a bundle with a missing file will not update the content. */
+ public void testMissingRequiredBundleFile() throws Exception {
+ ConfigBundle installedConfigBundle = createValidTzDataBundle("2030a");
+ assertTrue(install(installedConfigBundle));
+ assertTzDataInstalled(installedConfigBundle);
+
+ ConfigBundle incompleteUpdate =
+ createValidTzDataBundleBuilder("2030b").clearBionicTzData().buildUnvalidated();
+ assertFalse(install(incompleteUpdate));
+ assertTzDataInstalled(installedConfigBundle);
+ }
+
+ /**
+ * Tests that an update will be unpacked even if there is a partial update from a previous run.
+ */
+ public void testInstallWithWorkingDir() throws Exception {
+ File workingDir = new File(testInstallDir, TzDataBundleInstaller.WORKING_DIR_NAME);
+ assertTrue(workingDir.mkdir());
+ createFile(new File(workingDir, "myFile"));
+
+ ConfigBundle tzData = createValidTzDataBundle("2030a");
+ assertTrue(install(tzData));
+ assertTzDataInstalled(tzData);
+ }
+
+ /**
+ * Tests that a bundle with a checksum entry that references a missing file will not update the
+ * content.
+ */
+ public void testChecksumBundleEntry_fileMissing() throws Exception {
+ ConfigBundle badUpdate =
+ createValidTzDataBundleBuilder("2030b")
+ .addChecksum("/fileDoesNotExist", 1234)
+ .build();
+ assertFalse(install(badUpdate));
+ assertNoContentInstalled();
+ }
+
+ /**
+ * Tests that a bundle with a checksum entry with a bad checksum will not update the
+ * content.
+ */
+ public void testChecksumBundleEntry_incorrectChecksum() throws Exception {
+ File fileToChecksum = SYSTEM_ZONE_INFO_FILE;
+ long badChecksum = FileUtils.calculateChecksum(fileToChecksum) + 1;
+ ConfigBundle badUpdate =
+ createValidTzDataBundleBuilder("2030b")
+ .clearChecksumEntries()
+ .addChecksum(fileToChecksum.getPath(), badChecksum)
+ .build();
+ assertFalse(install(badUpdate));
+ assertNoContentInstalled();
+ }
+
+ private boolean install(ConfigBundle configBundle) throws Exception {
+ return installer.install(configBundle.getBundleBytes());
+ }
+
+ private ConfigBundle createValidTzDataBundle(String tzDataVersion)
+ throws IOException {
+ return createValidTzDataBundleBuilder(tzDataVersion).build();
+ }
+
+ private TzDataBundleBuilder createValidTzDataBundleBuilder(String tzDataVersion)
+ throws IOException {
+
+ // The file to include in the installation-time checksum check.
+ File fileToChecksum = SYSTEM_ZONE_INFO_FILE;
+ long checksum = FileUtils.calculateChecksum(fileToChecksum);
+
+ File bionicTzData = new File(tempDir, "zoneinfo");
+ createFile(bionicTzData);
+
+ File icuData = new File(tempDir, "icudata");
+ createFile(icuData);
+
+ return new TzDataBundleBuilder()
+ .addChecksum(fileToChecksum.getPath(), checksum)
+ .setTzDataVersion(tzDataVersion)
+ .addBionicTzData(bionicTzData)
+ .addIcuTzData(icuData);
+ }
+
+ private void assertTzDataInstalled(ConfigBundle expectedTzData) throws Exception {
+ assertTrue(testInstallDir.exists());
+
+ File currentTzDataDir = new File(testInstallDir, TzDataBundleInstaller.CURRENT_TZ_DATA_DIR_NAME);
+ assertTrue(currentTzDataDir.exists());
+
+ File checksumFile = new File(currentTzDataDir, ConfigBundle.CHECKSUMS_FILE_NAME);
+ assertTrue(checksumFile.exists());
+
+ File versionFile = new File(currentTzDataDir,
+ ConfigBundle.TZ_DATA_VERSION_FILE_NAME);
+ assertTrue(versionFile.exists());
+
+ File bionicFile = new File(currentTzDataDir, ConfigBundle.ZONEINFO_FILE_NAME);
+ assertTrue(bionicFile.exists());
+
+ File icuFile = new File(currentTzDataDir, ConfigBundle.ICU_DATA_FILE_NAME);
+ assertTrue(icuFile.exists());
+
+ // Also check no working directory is left lying around.
+ File workingDir = new File(testInstallDir, TzDataBundleInstaller.WORKING_DIR_NAME);
+ assertFalse(workingDir.exists());
+ }
+
+ private void assertNoContentInstalled() {
+ File currentTzDataDir = new File(testInstallDir, TzDataBundleInstaller.CURRENT_TZ_DATA_DIR_NAME);
+ assertFalse(currentTzDataDir.exists());
+
+ // Also check no working directories are left lying around.
+ File workingDir = new File(testInstallDir, TzDataBundleInstaller.WORKING_DIR_NAME);
+ assertFalse(workingDir.exists());
+
+ File oldDataDir = new File(testInstallDir, TzDataBundleInstaller.OLD_TZ_DATA_DIR_NAME);
+ assertFalse(oldDataDir.exists());
+ }
+
+ private static void createFile(File file) {
+ try (FileOutputStream fos = new FileOutputStream(file)) {
+ fos.write('a');
+ } catch (IOException e) {
+ fail(e.getMessage());
+ }
+ }
+}
diff --git a/tzdata/update_test_app/Android.mk b/tzdata/update_test_app/Android.mk
new file mode 100644
index 0000000..ee70819
--- /dev/null
+++ b/tzdata/update_test_app/Android.mk
@@ -0,0 +1,25 @@
+# Copyright (C) 2015 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE_TAGS := optional
+LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
+LOCAL_PROGUARD_ENABLED := disabled
+LOCAL_STATIC_JAVA_LIBRARIES := android-support-v4
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+LOCAL_PACKAGE_NAME := UpdateTestApp
+LOCAL_CERTIFICATE := platform
+include $(BUILD_PACKAGE)
diff --git a/tzdata/update_test_app/AndroidManifest.xml b/tzdata/update_test_app/AndroidManifest.xml
new file mode 100644
index 0000000..081aae5
--- /dev/null
+++ b/tzdata/update_test_app/AndroidManifest.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="libcore.tzdata.update_test_app.installupdatetestapp" >
+
+ <uses-permission android:name="android.permission.UPDATE_CONFIG" />
+
+ <application
+ android:allowBackup="false"
+ android:icon="@drawable/ic_launcher"
+ android:label="@string/app_name"
+ android:theme="@android:style/Theme.Holo.Light">
+ <activity
+ android:name=".MainActivity"
+ android:label="@string/app_name" >
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
+
+ <provider
+ android:name="android.support.v4.content.FileProvider"
+ android:authorities="libcore.tzdata.update_test_app.fileprovider"
+ android:grantUriPermissions="true"
+ android:exported="false">
+ <meta-data
+ android:name="android.support.FILE_PROVIDER_PATHS"
+ android:resource="@xml/filepaths" />
+ </provider>
+
+ </application>
+
+</manifest>
diff --git a/tzdata/update_test_app/res/drawable/ic_launcher.png b/tzdata/update_test_app/res/drawable/ic_launcher.png
new file mode 100644
index 0000000..96a442e
--- /dev/null
+++ b/tzdata/update_test_app/res/drawable/ic_launcher.png
Binary files differ
diff --git a/tzdata/update_test_app/res/layout/activity_main.xml b/tzdata/update_test_app/res/layout/activity_main.xml
new file mode 100644
index 0000000..b265837
--- /dev/null
+++ b/tzdata/update_test_app/res/layout/activity_main.xml
@@ -0,0 +1,106 @@
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical"
+ tools:context=".MainActivity">
+
+ <LinearLayout
+ android:orientation="horizontal"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content">
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/action"
+ android:id="@+id/action_label" />
+
+ <EditText
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:id="@+id/action"
+ android:layout_weight="1"
+ android:text="@string/default_action" />
+ </LinearLayout>
+
+ <LinearLayout
+ android:orientation="horizontal"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content">
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/version"
+ android:id="@+id/version_label" />
+
+ <EditText
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:id="@+id/version"
+ android:layout_weight="1"
+ android:text="@string/default_version" />
+ </LinearLayout>
+
+ <LinearLayout
+ android:orientation="horizontal"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content">
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/content_path"
+ android:id="@+id/content_path_label" />
+
+ <EditText
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:text="@string/default_content_path"
+ android:id="@+id/content_path" />
+
+ </LinearLayout>
+
+ <LinearLayout
+ android:orientation="horizontal"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content">
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/required_hash"
+ android:id="@+id/required_hash_label" />
+
+ <EditText
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:text="@string/default_required_hash"
+ android:id="@+id/required_hash" />
+
+ </LinearLayout>
+
+ <Button
+ android:id="@+id/trigger_install_button"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_centerHorizontal="true"
+ android:layout_centerVertical="true"
+ android:text="@string/trigger_install" />
+
+ <ScrollView
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:scrollbars="vertical"
+ android:fillViewport="true">
+
+ <TextView
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent"
+ android:id="@+id/log"
+ android:singleLine="false" />
+
+ </ScrollView>
+
+</LinearLayout>
diff --git a/tzdata/update_test_app/res/values/strings.xml b/tzdata/update_test_app/res/values/strings.xml
new file mode 100644
index 0000000..524f9d8
--- /dev/null
+++ b/tzdata/update_test_app/res/values/strings.xml
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <string name="app_name">InstallUpdateTestApp</string>
+ <string name="action">Action</string>
+ <string name="content_path">Content Path</string>
+ <string name="default_action">android.intent.action.UPDATE_TZDATA</string>
+ <string name="default_content_path">/data/local/tmp/out.zip</string>
+ <string name="default_required_hash">NONE</string>
+ <string name="default_version">1</string>
+ <string name="required_hash">Required Hash</string>
+ <string name="trigger_install">Trigger Install</string>
+ <string name="version">Version</string>
+</resources>
diff --git a/tzdata/update_test_app/res/xml/filepaths.xml b/tzdata/update_test_app/res/xml/filepaths.xml
new file mode 100644
index 0000000..c95b8f4
--- /dev/null
+++ b/tzdata/update_test_app/res/xml/filepaths.xml
@@ -0,0 +1,4 @@
+<!-- Used by FileProvider. See AndroidManifest.xml -->
+<paths>
+ <files-path path="temp/" name="temp" />
+</paths>
diff --git a/tzdata/update_test_app/src/libcore/tzdata/update_test_app/installupdatetestapp/MainActivity.java b/tzdata/update_test_app/src/libcore/tzdata/update_test_app/installupdatetestapp/MainActivity.java
new file mode 100644
index 0000000..2348e43
--- /dev/null
+++ b/tzdata/update_test_app/src/libcore/tzdata/update_test_app/installupdatetestapp/MainActivity.java
@@ -0,0 +1,173 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package libcore.tzdata.update_test_app.installupdatetestapp;
+
+import android.app.ActionBar;
+import android.app.Activity;
+import android.content.Intent;
+import android.net.Uri;
+import android.os.AsyncTask;
+import android.os.Bundle;
+import android.provider.Settings;
+import android.support.v4.content.FileProvider;
+import android.util.Base64;
+import android.view.View;
+import android.widget.Button;
+import android.widget.EditText;
+import android.widget.TextView;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.util.Date;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+
+
+public class MainActivity extends Activity implements View.OnClickListener {
+
+ private static final String EXTRA_REQUIRED_HASH = "REQUIRED_HASH";
+ private static final String EXTRA_VERSION_NUMBER = "VERSION";
+
+ private EditText actionEditText;
+ private EditText versionEditText;
+ private EditText contentPathEditText;
+ private EditText requiredHashEditText;
+ private TextView logView;
+
+ private ExecutorService executor;
+
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_main);
+ Button triggerInstallButton = (Button) findViewById(R.id.trigger_install_button);
+ triggerInstallButton.setOnClickListener(this);
+
+ actionEditText = (EditText) findViewById(R.id.action);
+ versionEditText = (EditText) findViewById(R.id.version);
+ contentPathEditText = (EditText) findViewById(R.id.content_path);
+ requiredHashEditText = (EditText) findViewById(R.id.required_hash);
+ logView = (TextView) findViewById(R.id.log);
+ executor = Executors.newFixedThreadPool(1);
+ }
+
+ @Override
+ public void onClick(View v) {
+ final String action = actionEditText.getText().toString();
+ final String contentPath = contentPathEditText.getText().toString();
+ final String version = versionEditText.getText().toString();
+ final String requiredHash = requiredHashEditText.getText().toString();
+
+ new AsyncTask<Void, String, Void>() {
+ @Override
+ protected Void doInBackground(Void... params) {
+ final File contentFile = new File(contentPath);
+ File tempDir = new File(getFilesDir(), "temp");
+ if (!tempDir.exists() && !tempDir.mkdir()) {
+ publishProgress("Unable to create: " + tempDir);
+ return null;
+ }
+
+ File copyOfContentFile;
+ try {
+ copyOfContentFile = File.createTempFile("content", ".tmp", tempDir);
+ copyFile(contentFile, copyOfContentFile);
+ } catch (IOException e) {
+ publishProgress("Error", exceptionToString(e));
+ return null;
+ }
+ publishProgress("Created copy of " + contentFile + " at " + copyOfContentFile);
+
+ try {
+ sendIntent(copyOfContentFile, action, version, requiredHash);
+ } catch (Exception e) {
+ publishProgress("Error", exceptionToString(e));
+ }
+ publishProgress("Update intent sent successfully");
+ return null;
+ }
+
+ @Override
+ protected void onProgressUpdate(String... values) {
+ for (String message : values) {
+ addToLog(message, null);
+ }
+ }
+ }.executeOnExecutor(executor);
+ }
+
+ private void sleep(long millisDelay) {
+ try {
+ Thread.sleep(millisDelay);
+ } catch (InterruptedException e) {
+ // Ignore
+ }
+ }
+
+ private void sendIntent(
+ File contentFile, String action, String version, String required) {
+ Intent i = new Intent();
+ i.setAction(action);
+ Uri contentUri =
+ FileProvider.getUriForFile(
+ getApplicationContext(), "libcore.tzdata.update_test_app.fileprovider",
+ contentFile);
+ i.setData(contentUri);
+ i.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
+ i.putExtra(EXTRA_VERSION_NUMBER, version);
+ i.putExtra(EXTRA_REQUIRED_HASH, required);
+ sendBroadcast(i);
+ }
+
+ private void addToLog(String message, Exception e) {
+ logString(message);
+ if (e != null) {
+ String text = exceptionToString(e);
+ logString(text);
+ }
+ }
+
+ private void logString(String value) {
+ logView.append(new Date() + " " + value + "\n");
+ int scrollAmount =
+ logView.getLayout().getLineTop(logView.getLineCount()) - logView.getHeight();
+ logView.scrollTo(0, scrollAmount);
+ }
+
+ private static String exceptionToString(Exception e) {
+ StringWriter writer = new StringWriter();
+ e.printStackTrace(new PrintWriter(writer));
+ return writer.getBuffer().toString();
+ }
+
+ private static void copyFile(File from, File to) throws IOException {
+ byte[] buffer = new byte[8192];
+ int count;
+ try (
+ FileInputStream in = new FileInputStream(from);
+ FileOutputStream out = new FileOutputStream(to)
+ ) {
+ while ((count = in.read(buffer)) != -1) {
+ out.write(buffer, 0, count);
+ }
+ }
+ }
+}