CipherTest: do not test known ciphertext for randomized algorithms
am: dfb337d6f7

Change-Id: Ia6cd7a7ef43094700d7dd2024a26f7ecd69a0116
diff --git a/luni/src/main/native/Register.cpp b/luni/src/main/native/Register.cpp
index 5fd4a7d..52df40e 100644
--- a/luni/src/main/native/Register.cpp
+++ b/luni/src/main/native/Register.cpp
@@ -53,3 +53,20 @@
 
     return JNI_VERSION_1_6;
 }
+
+// DalvikVM calls this on shutdown, do any global cleanup here.
+// -- Very important if we restart multiple DalvikVMs in the same process to reset the state.
+void JNI_OnUnload(JavaVM* vm, void*) {
+    JNIEnv* env;
+    if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) {
+        ALOGE("JavaVM::GetEnv() failed");
+        abort();
+    }
+    ALOGV("libjavacore JNI_OnUnload");
+
+    ScopedLocalFrame localFrame(env);
+
+#define UNREGISTER(FN) extern void FN(JNIEnv*); FN(env)
+    UNREGISTER(unregister_libcore_icu_ICU);
+#undef UNREGISTER
+}
diff --git a/luni/src/main/native/libcore_icu_ICU.cpp b/luni/src/main/native/libcore_icu_ICU.cpp
index 3eda923..e6f378e 100644
--- a/luni/src/main/native/libcore_icu_ICU.cpp
+++ b/luni/src/main/native/libcore_icu_ICU.cpp
@@ -838,56 +838,110 @@
     NATIVE_METHOD(ICU, toUpperCase, "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;"),
 };
 
+//
+// Global initialization & Teardown for ICU Setup
+//   - Contains handlers for JNI_OnLoad and JNI_OnUnload
+//
+
 #define FAIL_WITH_STRERROR(s) \
-    ALOGE("Couldn't " s " '%s': %s", path.c_str(), strerror(errno)); \
+    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()); \
+        ALOGE("Couldn't initialize ICU (" s "): %s (%s)", u_errorName(status), path_.c_str()); \
         return FALSE; \
     }
 
-static bool mapIcuData(const std::string& path) {
+// Contain the memory map for ICU data files.
+// Automatically adds the data file to ICU's list of data files upon constructing.
+//
+// - Automatically unmaps in the destructor.
+struct IcuDataMap {
+  // Map in ICU data at the path, returning null if it failed (prints error to ALOGE).
+  static std::unique_ptr<IcuDataMap> Create(const std::string& path) {
+    std::unique_ptr<IcuDataMap> map(new IcuDataMap(path));
+
+    if (!map->TryMap()) {
+      // madvise or ICU could fail but mmap still succeeds.
+      // Destructor will take care of cleaning up a partial init.
+      return nullptr;
+    }
+
+    return map;
+  }
+
+  // Unmap the ICU data.
+  ~IcuDataMap() {
+    TryUnmap();
+  }
+
+ private:
+  IcuDataMap(const std::string& path)
+    : path_(path),
+      data_(MAP_FAILED),
+      data_length_(0)
+  {}
+
+  bool TryMap() {
     // Open the file and get its length.
-    android::base::unique_fd fd(open(path.c_str(), O_RDONLY));
+    android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(path_.c_str(), O_RDONLY)));
+
     if (fd.get() == -1) {
         FAIL_WITH_STRERROR("open");
     }
+
     struct stat sb;
     if (fstat(fd.get(), &sb) == -1) {
         FAIL_WITH_STRERROR("stat");
     }
 
+    data_length_ = sb.st_size;
+
     // Map it.
-    void* data = mmap(NULL, sb.st_size, PROT_READ, MAP_SHARED, fd.get(), 0);
-    if (data == MAP_FAILED) {
+    data_ = mmap(NULL, data_length_, PROT_READ, MAP_SHARED, fd.get(), 0  /* offset */);
+    if (data_ == MAP_FAILED) {
         FAIL_WITH_STRERROR("mmap");
     }
 
     // Tell the kernel that accesses are likely to be random rather than sequential.
-    if (madvise(data, sb.st_size, MADV_RANDOM) == -1) {
+    if (madvise(data_, data_length_, MADV_RANDOM) == -1) {
         FAIL_WITH_STRERROR("madvise(MADV_RANDOM)");
     }
 
     UErrorCode status = U_ZERO_ERROR;
 
     // Tell ICU to use our memory-mapped data.
-    udata_setCommonData(data, &status);
+    udata_setCommonData(data_, &status);
     MAYBE_FAIL_WITH_ICU_ERROR("udata_setCommonData");
 
-    return TRUE;
-}
+    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();
+  bool TryUnmap() {
+    // Don't need to do opposite of udata_setCommonData,
+    // u_cleanup (performed in unregister_libcore_icu_ICU) takes care of it.
+
+    // Don't need to opposite of madvise, munmap will take care of it.
+
+    if (data_ != MAP_FAILED) {
+      if (munmap(data_, data_length_) == -1) {
+        FAIL_WITH_STRERROR("munmap");
+      }
     }
 
+    // Don't need to close the file, it was closed automatically during TryMap.
+    return true;
+  }
+
+  std::string path_;    // Save for error messages.
+  void* data_;          // Save for munmap.
+  size_t data_length_;  // Save for munmap.
+};
+
+struct ICURegistration {
+  // Init ICU, configuring it and loading the data files.
+  ICURegistration(JNIEnv* env) {
     UErrorCode status = U_ZERO_ERROR;
     // Tell ICU it can *only* use our memory-mapped data.
     udata_setFileAccess(UDATA_NO_FILES, &status);
@@ -896,15 +950,13 @@
         abort();
     }
 
-    // Map in optional TZ data files.
-    std::string dataPath;
-    dataPath = dataPathPrefix;
-    dataPath += "/misc/zoneinfo/current/icu/icu_tzdata.dat";
+    std::string dataPath = getTzDataOverridePath();
 
+    // Map in optional TZ data files.
     struct stat sb;
     if (stat(dataPath.c_str(), &sb) == 0) {
         ALOGD("Timezone override file found: %s", dataPath.c_str());
-        if (!mapIcuData(dataPath)) {
+        if ((icu_datamap_from_data_ = IcuDataMap::Create(dataPath)) == nullptr) {
             ALOGW("TZ override file %s exists but could not be loaded. Skipping.", dataPath.c_str());
         }
     } else {
@@ -912,18 +964,7 @@
     }
 
     // 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)) {
+    if ((icu_datamap_from_system_ = IcuDataMap::Create(getSystemPath())) == nullptr) {
         abort();
     }
 
@@ -937,4 +978,69 @@
     }
 
     jniRegisterNativeMethods(env, "libcore/icu/ICU", gMethods, NELEM(gMethods));
+  }
+
+  // De-init ICU, unloading the data files. Do the opposite of the above function.
+  ~ICURegistration() {
+    // Skip unregistering JNI methods explicitly, class unloading takes care of it.
+
+    // Reset libicu state to before it was loaded.
+    u_cleanup();
+
+    // Unmap ICU data files that shipped with the device for everything else.
+    icu_datamap_from_system_.reset();
+
+    // Unmap optional TZ data files.
+    icu_datamap_from_data_.reset();
+
+    // We don't need to call udata_setFileAccess because u_cleanup takes care of it.
+  }
+
+  // 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.
+  static std::string getTzDataOverridePath() {
+    const char* dataPathPrefix = getenv("ANDROID_DATA");
+    if (dataPathPrefix == NULL) {
+      ALOGE("ANDROID_DATA environment variable not set"); \
+      abort();
+    }
+    std::string dataPath;
+    dataPath = dataPathPrefix;
+    dataPath += "/misc/zoneinfo/current/icu/icu_tzdata.dat";
+
+    return dataPath;
+  }
+
+  static std::string getSystemPath() {
+    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";
+    return systemPath;
+  }
+
+  std::unique_ptr<IcuDataMap> icu_datamap_from_data_;
+  std::unique_ptr<IcuDataMap> icu_datamap_from_system_;
+};
+
+// Use RAII-style initialization/teardown so that we can get unregistered
+// when dlclose is called (even if JNI_OnUnload is not).
+static std::unique_ptr<ICURegistration> sIcuRegistration;
+
+// Init ICU, configuring it and loading the data files.
+void register_libcore_icu_ICU(JNIEnv* env) {
+  sIcuRegistration.reset(new ICURegistration(env));
+}
+
+// De-init ICU, unloading the data files. Do the opposite of the above function.
+void unregister_libcore_icu_ICU(JNIEnv*) {
+  // Explicitly calling this is optional. Dlclose will take care of it as well.
+  sIcuRegistration.reset();
 }
diff --git a/luni/src/test/java/libcore/java/net/SocketTest.java b/luni/src/test/java/libcore/java/net/SocketTest.java
index f273f8e..1952286 100644
--- a/luni/src/test/java/libcore/java/net/SocketTest.java
+++ b/luni/src/test/java/libcore/java/net/SocketTest.java
@@ -16,6 +16,7 @@
 
 package libcore.java.net;
 
+import java.io.FileDescriptor;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
@@ -43,7 +44,6 @@
 import java.util.concurrent.Executors;
 import java.util.concurrent.Future;
 import java.util.concurrent.TimeUnit;
-import java.io.FileDescriptor;
 
 
 public class SocketTest extends junit.framework.TestCase {
@@ -379,33 +379,43 @@
 
     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()
+        // Executes a connect() that should block.
+        Callable<String> connectWorker = () -> {
+            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 */);
+                return "Connect returned unexpectedly for: " + unreachableIp;
+            } catch (SocketException expected) {
+                signal.countDown();
+                return expected.getMessage().contains("Socket closed")
+                        ? null
+                        : "Unexpected SocketException message: " + expected.getMessage();
+            } catch (IOException e) {
+                return "Unexpected exception: " + e;
+            }
+        };
+        Future<String> connectResult =
+                Executors.newSingleThreadScheduledExecutor().submit(connectWorker);
+
+        // Wait sufficient time for the connectWorker thread to run and start connect().
         Thread.sleep(2000);
 
+        // Close the socket that connectWorker should currently be blocked in connect().
         s.close();
 
+        // connectWorker should have been unblocked so await() should return true.
         boolean connectUnblocked = signal.await(2000, TimeUnit.MILLISECONDS);
-        assertTrue(connectUnblocked);
+
+        // connectWorker should have returned null if everything went as expected.
+        String workerFailure = connectResult.get(2000, TimeUnit.MILLISECONDS);
+
+        assertTrue("connectUnblocked=[" + connectUnblocked
+                + "], workerFailure=[" + workerFailure + "]",
+                connectUnblocked && workerFailure == null);
     }
 
     // http://b/29092095