Merge "liblp: Improve reliability of UpdatePartitionTable."
diff --git a/libcutils/Android.bp b/libcutils/Android.bp
index cdbb65f..58e59d6 100644
--- a/libcutils/Android.bp
+++ b/libcutils/Android.bp
@@ -65,7 +65,6 @@
         "iosched_policy.cpp",
         "load_file.cpp",
         "native_handle.cpp",
-        "open_memstream.c",
         "record_stream.cpp",
         "sched_policy.cpp",
         "sockets.cpp",
diff --git a/libcutils/hashmap.cpp b/libcutils/hashmap.cpp
index 10e3b25..2a4a52e 100644
--- a/libcutils/hashmap.cpp
+++ b/libcutils/hashmap.cpp
@@ -36,7 +36,7 @@
     size_t bucketCount;
     int (*hash)(void* key);
     bool (*equals)(void* keyA, void* keyB);
-    mutex_t lock; 
+    mutex_t lock;
     size_t size;
 };
 
@@ -44,18 +44,18 @@
         int (*hash)(void* key), bool (*equals)(void* keyA, void* keyB)) {
     assert(hash != NULL);
     assert(equals != NULL);
-    
+
     Hashmap* map = static_cast<Hashmap*>(malloc(sizeof(Hashmap)));
     if (map == NULL) {
         return NULL;
     }
-    
+
     // 0.75 load factor.
     size_t minimumBucketCount = initialCapacity * 4 / 3;
     map->bucketCount = 1;
     while (map->bucketCount <= minimumBucketCount) {
         // Bucket count must be power of 2.
-        map->bucketCount <<= 1; 
+        map->bucketCount <<= 1;
     }
 
     map->buckets = static_cast<Entry**>(calloc(map->bucketCount, sizeof(Entry*)));
@@ -63,14 +63,14 @@
         free(map);
         return NULL;
     }
-    
+
     map->size = 0;
 
     map->hash = hash;
     map->equals = equals;
-    
+
     mutex_init(&map->lock);
-    
+
     return map;
 }
 
@@ -89,12 +89,8 @@
     h ^= (((unsigned int) h) >> 14);
     h += (h << 4);
     h ^= (((unsigned int) h) >> 10);
-       
-    return h;
-}
 
-size_t hashmapSize(Hashmap* map) {
-    return map->size;
+    return h;
 }
 
 static inline size_t calculateIndex(size_t bucketCount, int hash) {
@@ -111,7 +107,7 @@
             // Abort expansion.
             return;
         }
-        
+
         // Move over existing entries.
         size_t i;
         for (i = 0; i < map->bucketCount; i++) {
@@ -240,54 +236,6 @@
     return NULL;
 }
 
-bool hashmapContainsKey(Hashmap* map, void* key) {
-    int hash = hashKey(map, key);
-    size_t index = calculateIndex(map->bucketCount, hash);
-
-    Entry* entry = map->buckets[index];
-    while (entry != NULL) {
-        if (equalKeys(entry->key, entry->hash, key, hash, map->equals)) {
-            return true;
-        }
-        entry = entry->next;
-    }
-
-    return false;
-}
-
-void* hashmapMemoize(Hashmap* map, void* key, 
-        void* (*initialValue)(void* key, void* context), void* context) {
-    int hash = hashKey(map, key);
-    size_t index = calculateIndex(map->bucketCount, hash);
-
-    Entry** p = &(map->buckets[index]);
-    while (true) {
-        Entry* current = *p;
-
-        // Add a new entry.
-        if (current == NULL) {
-            *p = createEntry(key, hash, NULL);
-            if (*p == NULL) {
-                errno = ENOMEM;
-                return NULL;
-            }
-            void* value = initialValue(key, context);
-            (*p)->value = value;
-            map->size++;
-            expandIfNecessary(map);
-            return value;
-        }
-
-        // Return existing value.
-        if (equalKeys(current->key, current->hash, key, hash, map->equals)) {
-            return current->value;
-        }
-
-        // Move to next entry.
-        p = &current->next;
-    }
-}
-
 void* hashmapRemove(Hashmap* map, void* key) {
     int hash = hashKey(map, key);
     size_t index = calculateIndex(map->bucketCount, hash);
@@ -310,9 +258,8 @@
     return NULL;
 }
 
-void hashmapForEach(Hashmap* map, 
-        bool (*callback)(void* key, void* value, void* context),
-        void* context) {
+void hashmapForEach(Hashmap* map, bool (*callback)(void* key, void* value, void* context),
+                    void* context) {
     size_t i;
     for (i = 0; i < map->bucketCount; i++) {
         Entry* entry = map->buckets[i];
@@ -325,34 +272,3 @@
         }
     }
 }
-
-size_t hashmapCurrentCapacity(Hashmap* map) {
-    size_t bucketCount = map->bucketCount;
-    return bucketCount * 3 / 4;
-}
-
-size_t hashmapCountCollisions(Hashmap* map) {
-    size_t collisions = 0;
-    size_t i;
-    for (i = 0; i < map->bucketCount; i++) {
-        Entry* entry = map->buckets[i];
-        while (entry != NULL) {
-            if (entry->next != NULL) {
-                collisions++;
-            }
-            entry = entry->next;
-        }
-    }
-    return collisions;
-}
-
-int hashmapIntHash(void* key) {
-    // Return the key value itself.
-    return *((int*) key);
-}
-
-bool hashmapIntEquals(void* keyA, void* keyB) {
-    int a = *((int*) keyA);
-    int b = *((int*) keyB);
-    return a == b;
-}
diff --git a/libcutils/include/cutils/hashmap.h b/libcutils/include/cutils/hashmap.h
index 5cb344c..9cfd669 100644
--- a/libcutils/include/cutils/hashmap.h
+++ b/libcutils/include/cutils/hashmap.h
@@ -16,6 +16,9 @@
 
 /**
  * Hash map.
+ *
+ * Use std::map or std::unordered_map instead.
+ * https://en.cppreference.com/w/cpp/container
  */
 
 #ifndef __HASHMAP_H
@@ -68,38 +71,17 @@
 void* hashmapGet(Hashmap* map, void* key);
 
 /**
- * Returns true if the map contains an entry for the given key.
- */
-bool hashmapContainsKey(Hashmap* map, void* key);
-
-/**
- * Gets the value for a key. If a value is not found, this function gets a 
- * value and creates an entry using the given callback.
- *
- * If memory allocation fails, the callback is not called, this function
- * returns NULL, and errno is set to ENOMEM.
- */
-void* hashmapMemoize(Hashmap* map, void* key, 
-        void* (*initialValue)(void* key, void* context), void* context);
-
-/**
  * Removes an entry from the map. Returns the removed value or NULL if no
  * entry was present.
  */
 void* hashmapRemove(Hashmap* map, void* key);
 
 /**
- * Gets the number of entries in this map.
- */
-size_t hashmapSize(Hashmap* map);
-
-/**
  * Invokes the given callback on each entry in the map. Stops iterating if
  * the callback returns false.
  */
-void hashmapForEach(Hashmap* map, 
-        bool (*callback)(void* key, void* value, void* context),
-        void* context);
+void hashmapForEach(Hashmap* map, bool (*callback)(void* key, void* value, void* context),
+                    void* context);
 
 /**
  * Concurrency support.
@@ -115,36 +97,8 @@
  */
 void hashmapUnlock(Hashmap* map);
 
-/**
- * Key utilities.
- */
-
-/**
- * Hashes int keys. 'key' is a pointer to int.
- */
-int hashmapIntHash(void* key);
-
-/**
- * Compares two int keys for equality.
- */
-bool hashmapIntEquals(void* keyA, void* keyB);
-
-/**
- * For debugging.
- */
-
-/**
- * Gets current capacity.
- */
-size_t hashmapCurrentCapacity(Hashmap* map);
-
-/**
- * Counts the number of entry collisions.
- */
-size_t hashmapCountCollisions(Hashmap* map);
-
 #ifdef __cplusplus
 }
 #endif
 
-#endif /* __HASHMAP_H */ 
+#endif /* __HASHMAP_H */
diff --git a/libcutils/include/cutils/open_memstream.h b/libcutils/include/cutils/open_memstream.h
deleted file mode 100644
index c1a81eb..0000000
--- a/libcutils/include/cutils/open_memstream.h
+++ /dev/null
@@ -1,36 +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.
- */
-
-#ifndef __CUTILS_OPEN_MEMSTREAM_H__
-#define __CUTILS_OPEN_MEMSTREAM_H__
-
-#include <stdio.h>
-
-#if defined(__APPLE__)
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-FILE* open_memstream(char** bufp, size_t* sizep);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* __APPLE__ */
-
-#endif /*__CUTILS_OPEN_MEMSTREAM_H__*/
diff --git a/libcutils/include_vndk/cutils/open_memstream.h b/libcutils/include_vndk/cutils/open_memstream.h
deleted file mode 120000
index c894084..0000000
--- a/libcutils/include_vndk/cutils/open_memstream.h
+++ /dev/null
@@ -1 +0,0 @@
-../../include/cutils/open_memstream.h
\ No newline at end of file
diff --git a/libcutils/open_memstream.c b/libcutils/open_memstream.c
deleted file mode 100644
index 9183266..0000000
--- a/libcutils/open_memstream.c
+++ /dev/null
@@ -1,373 +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.
- */
-
-#if defined(__APPLE__)
-
-/*
- * Implementation of the POSIX open_memstream() function, which Linux has
- * but BSD lacks.
- *
- * Summary:
- * - Works like a file-backed FILE* opened with fopen(name, "w"), but the
- *   backing is a chunk of memory rather than a file.
- * - The buffer expands as you write more data.  Seeking past the end
- *   of the file and then writing to it zero-fills the gap.
- * - The values at "*bufp" and "*sizep" should be considered read-only,
- *   and are only valid immediately after an fflush() or fclose().
- * - A '\0' is maintained just past the end of the file. This is not included
- *   in "*sizep".  (The behavior w.r.t. fseek() is not clearly defined.
- *   The spec says the null byte is written when a write() advances EOF,
- *   but it looks like glibc ensures the null byte is always found at EOF,
- *   even if you just seeked backwards.  The example on the opengroup.org
- *   page suggests that this is the expected behavior.  The null must be
- *   present after a no-op fflush(), which we can't see, so we have to save
- *   and restore it.  Annoying, but allows file truncation.)
- * - After fclose(), the caller must eventually free(*bufp).
- *
- * This is built out of funopen(), which BSD has but Linux lacks.  There is
- * no flush() operator, so we need to keep the user pointers up to date
- * after each operation.
- *
- * I don't think Windows has any of the above, but we don't need to use
- * them there, so we just supply a stub.
- */
-#include <cutils/open_memstream.h>
-#include <stdlib.h>
-#include <sys/types.h>
-#include <unistd.h>
-#include <stdio.h>
-#include <string.h>
-#include <errno.h>
-#include <assert.h>
-
-#if 0
-# define DBUG(x) printf x
-#else
-# define DBUG(x) ((void)0)
-#endif
-
-/*
- * Definition of a seekable, write-only memory stream.
- */
-typedef struct {
-    char**      bufp;       /* pointer to buffer pointer */
-    size_t*     sizep;      /* pointer to eof */
-
-    size_t      allocSize;  /* size of buffer */
-    size_t      eof;        /* furthest point we've written to */
-    size_t      offset;     /* current write offset */
-    char        saved;      /* required by NUL handling */
-} MemStream;
-
-#define kInitialSize    1024
-
-/*
- * Ensure that we have enough storage to write "size" bytes at the
- * current offset.  We also have to take into account the extra '\0'
- * that we maintain just past EOF.
- *
- * Returns 0 on success.
- */
-static int ensureCapacity(MemStream* stream, int writeSize)
-{
-    DBUG(("+++ ensureCap off=%d size=%d\n", stream->offset, writeSize));
-
-    size_t neededSize = stream->offset + writeSize + 1;
-    if (neededSize <= stream->allocSize)
-        return 0;
-
-    size_t newSize;
-
-    if (stream->allocSize == 0) {
-        newSize = kInitialSize;
-    } else {
-        newSize = stream->allocSize;
-        newSize += newSize / 2;             /* expand by 3/2 */
-    }
-
-    if (newSize < neededSize)
-        newSize = neededSize;
-    DBUG(("+++ realloc %p->%p to size=%d\n",
-        stream->bufp, *stream->bufp, newSize));
-    char* newBuf = (char*) realloc(*stream->bufp, newSize);
-    if (newBuf == NULL)
-        return -1;
-
-    *stream->bufp = newBuf;
-    stream->allocSize = newSize;
-    return 0;
-}
-
-/*
- * Write data to a memstream, expanding the buffer if necessary.
- *
- * If we previously seeked beyond EOF, zero-fill the gap.
- *
- * Returns the number of bytes written.
- */
-static int write_memstream(void* cookie, const char* buf, int size)
-{
-    MemStream* stream = (MemStream*) cookie;
-
-    if (ensureCapacity(stream, size) < 0)
-        return -1;
-
-    /* seeked past EOF earlier? */
-    if (stream->eof < stream->offset) {
-        DBUG(("+++ zero-fill gap from %d to %d\n",
-            stream->eof, stream->offset-1));
-        memset(*stream->bufp + stream->eof, '\0',
-            stream->offset - stream->eof);
-    }
-
-    /* copy data, advance write pointer */
-    memcpy(*stream->bufp + stream->offset, buf, size);
-    stream->offset += size;
-
-    if (stream->offset > stream->eof) {
-        /* EOF has advanced, update it and append null byte */
-        DBUG(("+++ EOF advanced to %d, appending nul\n", stream->offset));
-        assert(stream->offset < stream->allocSize);
-        stream->eof = stream->offset;
-    } else {
-        /* within previously-written area; save char we're about to stomp */
-        DBUG(("+++ within written area, saving '%c' at %d\n",
-            *(*stream->bufp + stream->offset), stream->offset));
-        stream->saved = *(*stream->bufp + stream->offset);
-    }
-    *(*stream->bufp + stream->offset) = '\0';
-    *stream->sizep = stream->offset;
-
-    return size;
-}
-
-/*
- * Seek within a memstream.
- *
- * Returns the new offset, or -1 on failure.
- */
-static fpos_t seek_memstream(void* cookie, fpos_t offset, int whence)
-{
-    MemStream* stream = (MemStream*) cookie;
-    off_t newPosn = (off_t) offset;
-
-    if (whence == SEEK_CUR) {
-        newPosn += stream->offset;
-    } else if (whence == SEEK_END) {
-        newPosn += stream->eof;
-    }
-
-    if (newPosn < 0 || ((fpos_t)((size_t) newPosn)) != newPosn) {
-        /* bad offset - negative or huge */
-        DBUG(("+++ bogus seek offset %ld\n", (long) newPosn));
-        errno = EINVAL;
-        return (fpos_t) -1;
-    }
-
-    if (stream->offset < stream->eof) {
-        /*
-         * We were pointing to an area we'd already written to, which means
-         * we stomped on a character and must now restore it.
-         */
-        DBUG(("+++ restoring char '%c' at %d\n",
-            stream->saved, stream->offset));
-        *(*stream->bufp + stream->offset) = stream->saved;
-    }
-
-    stream->offset = (size_t) newPosn;
-
-    if (stream->offset < stream->eof) {
-        /*
-         * We're seeked backward into the stream.  Preserve the character
-         * at EOF and stomp it with a NUL.
-         */
-        stream->saved = *(*stream->bufp + stream->offset);
-        *(*stream->bufp + stream->offset) = '\0';
-        *stream->sizep = stream->offset;
-    } else {
-        /*
-         * We're positioned at, or possibly beyond, the EOF.  We want to
-         * publish the current EOF, not the current position.
-         */
-        *stream->sizep = stream->eof;
-    }
-
-    return newPosn;
-}
-
-/*
- * Close the memstream.  We free everything but the data buffer.
- */
-static int close_memstream(void* cookie)
-{
-    free(cookie);
-    return 0;
-}
-
-/*
- * Prepare a memstream.
- */
-FILE* open_memstream(char** bufp, size_t* sizep)
-{
-    FILE* fp;
-    MemStream* stream;
-
-    if (bufp == NULL || sizep == NULL) {
-        errno = EINVAL;
-        return NULL;
-    }
-
-    stream = (MemStream*) calloc(1, sizeof(MemStream));
-    if (stream == NULL)
-        return NULL;
-
-    fp = funopen(stream,
-        NULL, write_memstream, seek_memstream, close_memstream);
-    if (fp == NULL) {
-        free(stream);
-        return NULL;
-    }
-
-    *sizep = 0;
-    *bufp = NULL;
-    stream->bufp = bufp;
-    stream->sizep = sizep;
-
-    return fp;
-}
-
-
-
-
-#if 0
-#define _GNU_SOURCE
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-/*
- * Simple regression test.
- *
- * To test on desktop Linux with valgrind, it's possible to make a simple
- * change to open_memstream() to use fopencookie instead:
- *
- *  cookie_io_functions_t iofuncs =
- *      { NULL, write_memstream, seek_memstream, close_memstream };
- *  fp = fopencookie(stream, "w", iofuncs);
- *
- * (Some tweaks to seek_memstream are also required, as that takes a
- * pointer to an offset rather than an offset, and returns 0 or -1.)
- */
-int testMemStream(void)
-{
-    FILE *stream;
-    char *buf;
-    size_t len;
-    off_t eob;
-
-    printf("Test1\n");
-
-    /* std example */
-    stream = open_memstream(&buf, &len);
-    fprintf(stream, "hello my world");
-    fflush(stream);
-    printf("buf=%s, len=%zu\n", buf, len);
-    eob = ftello(stream);
-    fseeko(stream, 0, SEEK_SET);
-    fprintf(stream, "good-bye");
-    fseeko(stream, eob, SEEK_SET);
-    fclose(stream);
-    printf("buf=%s, len=%zu\n", buf, len);
-    free(buf);
-
-    printf("Test2\n");
-
-    /* std example without final seek-to-end */
-    stream = open_memstream(&buf, &len);
-    fprintf(stream, "hello my world");
-    fflush(stream);
-    printf("buf=%s, len=%zu\n", buf, len);
-    eob = ftello(stream);
-    fseeko(stream, 0, SEEK_SET);
-    fprintf(stream, "good-bye");
-    //fseeko(stream, eob, SEEK_SET);
-    fclose(stream);
-    printf("buf=%s, len=%zu\n", buf, len);
-    free(buf);
-
-    printf("Test3\n");
-
-    /* fancy example; should expand buffer with writes */
-    static const int kCmpLen = 1024 + 128;
-    char* cmp = malloc(kCmpLen);
-    memset(cmp, 0, 1024);
-    memset(cmp+1024, 0xff, kCmpLen-1024);
-    sprintf(cmp, "This-is-a-tes1234");
-    sprintf(cmp + 1022, "abcdef");
-
-    stream = open_memstream (&buf, &len);
-    setvbuf(stream, NULL, _IONBF, 0);   /* note: crashes in glibc with this */
-    fprintf(stream, "This-is-a-test");
-    fseek(stream, -1, SEEK_CUR);    /* broken in glibc; can use {13,SEEK_SET} */
-    fprintf(stream, "1234");
-    fseek(stream, 1022, SEEK_SET);
-    fputc('a', stream);
-    fputc('b', stream);
-    fputc('c', stream);
-    fputc('d', stream);
-    fputc('e', stream);
-    fputc('f', stream);
-    fflush(stream);
-
-    if (memcmp(buf, cmp, len+1) != 0) {
-        printf("mismatch\n");
-    } else {
-        printf("match\n");
-    }
-
-    printf("Test4\n");
-    stream = open_memstream (&buf, &len);
-    fseek(stream, 5000, SEEK_SET);
-    fseek(stream, 4096, SEEK_SET);
-    fseek(stream, -1, SEEK_SET);        /* should have no effect */
-    fputc('x', stream);
-    if (ftell(stream) == 4097)
-        printf("good\n");
-    else
-        printf("BAD: offset is %ld\n", ftell(stream));
-
-    printf("DONE\n");
-
-    return 0;
-}
-
-/* expected output:
-Test1
-buf=hello my world, len=14
-buf=good-bye world, len=14
-Test2
-buf=hello my world, len=14
-buf=good-bye, len=8
-Test3
-match
-Test4
-good
-DONE
-*/
-
-#endif
-
-#endif /* __APPLE__ */
diff --git a/libcutils/str_parms.cpp b/libcutils/str_parms.cpp
index f5a52a7..d818c51 100644
--- a/libcutils/str_parms.cpp
+++ b/libcutils/str_parms.cpp
@@ -354,12 +354,8 @@
 char *str_parms_to_str(struct str_parms *str_parms)
 {
     char *str = NULL;
-
-    if (hashmapSize(str_parms->map) > 0)
-        hashmapForEach(str_parms->map, combine_strings, &str);
-    else
-        str = strdup("");
-    return str;
+    hashmapForEach(str_parms->map, combine_strings, &str);
+    return (str != NULL) ? str : strdup("");
 }
 
 static bool dump_entry(void* key, void* value, void* /*context*/) {
diff --git a/libnativeloader/include/nativeloader/native_loader.h b/libnativeloader/include/nativeloader/native_loader.h
index 3563fc1..19a1783 100644
--- a/libnativeloader/include/nativeloader/native_loader.h
+++ b/libnativeloader/include/nativeloader/native_loader.h
@@ -53,8 +53,21 @@
 #if defined(__ANDROID__)
 // Look up linker namespace by class_loader. Returns nullptr if
 // there is no namespace associated with the class_loader.
+// TODO(b/79940628): move users to FindNativeLoaderNamespaceByClassLoader and remove this function.
 __attribute__((visibility("default")))
 android_namespace_t* FindNamespaceByClassLoader(JNIEnv* env, jobject class_loader);
+// That version works with native bridge namespaces, but requires use of OpenNativeLibrary.
+class NativeLoaderNamespace;
+__attribute__((visibility("default")))
+NativeLoaderNamespace* FindNativeLoaderNamespaceByClassLoader(
+    JNIEnv* env, jobject class_loader);
+// Load library.  Unlinke OpenNativeLibrary above couldn't create namespace on demand, but does
+// not require access to JNIEnv either.
+__attribute__((visibility("default")))
+void* OpenNativeLibrary(NativeLoaderNamespace* ns,
+                        const char* path,
+                        bool* needs_native_bridge,
+                        std::string* error_msg);
 #endif
 
 __attribute__((visibility("default")))
diff --git a/libnativeloader/native_loader.cpp b/libnativeloader/native_loader.cpp
index 7fef106..67c1c10 100644
--- a/libnativeloader/native_loader.cpp
+++ b/libnativeloader/native_loader.cpp
@@ -29,6 +29,7 @@
 #include "nativebridge/native_bridge.h"
 
 #include <algorithm>
+#include <list>
 #include <memory>
 #include <mutex>
 #include <string>
@@ -150,15 +151,14 @@
  public:
   LibraryNamespaces() : initialized_(false) { }
 
-  bool Create(JNIEnv* env,
-              uint32_t target_sdk_version,
-              jobject class_loader,
-              bool is_shared,
-              bool is_for_vendor,
-              jstring java_library_path,
-              jstring java_permitted_path,
-              NativeLoaderNamespace* ns,
-              std::string* error_msg) {
+  NativeLoaderNamespace* Create(JNIEnv* env,
+                                uint32_t target_sdk_version,
+                                jobject class_loader,
+                                bool is_shared,
+                                bool is_for_vendor,
+                                jstring java_library_path,
+                                jstring java_permitted_path,
+                                std::string* error_msg) {
     std::string library_path; // empty string by default.
 
     if (java_library_path != nullptr) {
@@ -182,10 +182,10 @@
     }
 
     if (!initialized_ && !InitPublicNamespace(library_path.c_str(), error_msg)) {
-      return false;
+      return nullptr;
     }
 
-    bool found = FindNamespaceByClassLoader(env, class_loader, nullptr);
+    bool found = FindNamespaceByClassLoader(env, class_loader);
 
     LOG_ALWAYS_FATAL_IF(found,
                         "There is already a namespace associated with this classloader");
@@ -199,13 +199,12 @@
       namespace_type |= ANDROID_NAMESPACE_TYPE_GREYLIST_ENABLED;
     }
 
-    NativeLoaderNamespace parent_ns;
-    bool found_parent_namespace = FindParentNamespaceByClassLoader(env, class_loader, &parent_ns);
+    NativeLoaderNamespace* parent_ns = FindParentNamespaceByClassLoader(env, class_loader);
 
     bool is_native_bridge = false;
 
-    if (found_parent_namespace) {
-      is_native_bridge = !parent_ns.is_android_namespace();
+    if (parent_ns != nullptr) {
+      is_native_bridge = !parent_ns->is_android_namespace();
     } else if (!library_path.empty()) {
       is_native_bridge = NativeBridgeIsPathSupported(library_path.c_str());
     }
@@ -251,15 +250,17 @@
 
     NativeLoaderNamespace native_loader_ns;
     if (!is_native_bridge) {
+      android_namespace_t* android_parent_ns =
+          parent_ns == nullptr ? nullptr : parent_ns->get_android_ns();
       android_namespace_t* ns = android_create_namespace(namespace_name,
                                                          nullptr,
                                                          library_path.c_str(),
                                                          namespace_type,
                                                          permitted_path.c_str(),
-                                                         parent_ns.get_android_ns());
+                                                         android_parent_ns);
       if (ns == nullptr) {
         *error_msg = dlerror();
-        return false;
+        return nullptr;
       }
 
       // Note that when vendor_ns is not configured this function will return nullptr
@@ -269,49 +270,50 @@
 
       if (!android_link_namespaces(ns, nullptr, system_exposed_libraries.c_str())) {
         *error_msg = dlerror();
-        return false;
+        return nullptr;
       }
 
       if (vndk_ns != nullptr && !system_vndksp_libraries_.empty()) {
         // vendor apks are allowed to use VNDK-SP libraries.
         if (!android_link_namespaces(ns, vndk_ns, system_vndksp_libraries_.c_str())) {
           *error_msg = dlerror();
-          return false;
+          return nullptr;
         }
       }
 
       if (!vendor_public_libraries_.empty()) {
         if (!android_link_namespaces(ns, vendor_ns, vendor_public_libraries_.c_str())) {
           *error_msg = dlerror();
-          return false;
+          return nullptr;
         }
       }
 
       native_loader_ns = NativeLoaderNamespace(ns);
     } else {
+      native_bridge_namespace_t* native_bridge_parent_namespace =
+          parent_ns == nullptr ? nullptr : parent_ns->get_native_bridge_ns();
       native_bridge_namespace_t* ns = NativeBridgeCreateNamespace(namespace_name,
                                                                   nullptr,
                                                                   library_path.c_str(),
                                                                   namespace_type,
                                                                   permitted_path.c_str(),
-                                                                  parent_ns.get_native_bridge_ns());
-
+                                                                  native_bridge_parent_namespace);
       if (ns == nullptr) {
         *error_msg = NativeBridgeGetError();
-        return false;
+        return nullptr;
       }
 
       native_bridge_namespace_t* vendor_ns = NativeBridgeGetVendorNamespace();
 
       if (!NativeBridgeLinkNamespaces(ns, nullptr, system_exposed_libraries.c_str())) {
         *error_msg = NativeBridgeGetError();
-        return false;
+        return nullptr;
       }
 
       if (!vendor_public_libraries_.empty()) {
         if (!NativeBridgeLinkNamespaces(ns, vendor_ns, vendor_public_libraries_.c_str())) {
           *error_msg = NativeBridgeGetError();
-          return false;
+          return nullptr;
         }
       }
 
@@ -320,24 +322,19 @@
 
     namespaces_.push_back(std::make_pair(env->NewWeakGlobalRef(class_loader), native_loader_ns));
 
-    *ns = native_loader_ns;
-    return true;
+    return &(namespaces_.back().second);
   }
 
-  bool FindNamespaceByClassLoader(JNIEnv* env, jobject class_loader, NativeLoaderNamespace* ns) {
+  NativeLoaderNamespace* FindNamespaceByClassLoader(JNIEnv* env, jobject class_loader) {
     auto it = std::find_if(namespaces_.begin(), namespaces_.end(),
                 [&](const std::pair<jweak, NativeLoaderNamespace>& value) {
                   return env->IsSameObject(value.first, class_loader);
                 });
     if (it != namespaces_.end()) {
-      if (ns != nullptr) {
-        *ns = it->second;
-      }
-
-      return true;
+      return &it->second;
     }
 
-    return false;
+    return nullptr;
   }
 
   void Initialize() {
@@ -557,24 +554,23 @@
     return env->CallObjectMethod(class_loader, get_parent);
   }
 
-  bool FindParentNamespaceByClassLoader(JNIEnv* env,
-                                        jobject class_loader,
-                                        NativeLoaderNamespace* ns) {
+  NativeLoaderNamespace* FindParentNamespaceByClassLoader(JNIEnv* env, jobject class_loader) {
     jobject parent_class_loader = GetParentClassLoader(env, class_loader);
 
     while (parent_class_loader != nullptr) {
-      if (FindNamespaceByClassLoader(env, parent_class_loader, ns)) {
-        return true;
+      NativeLoaderNamespace* ns;
+      if ((ns = FindNamespaceByClassLoader(env, parent_class_loader)) != nullptr) {
+        return ns;
       }
 
       parent_class_loader = GetParentClassLoader(env, parent_class_loader);
     }
 
-    return false;
+    return nullptr;
   }
 
   bool initialized_;
-  std::vector<std::pair<jweak, NativeLoaderNamespace>> namespaces_;
+  std::list<std::pair<jweak, NativeLoaderNamespace>> namespaces_;
   std::string system_public_libraries_;
   std::string vendor_public_libraries_;
   std::string oem_public_libraries_;
@@ -614,7 +610,6 @@
   std::lock_guard<std::mutex> guard(g_namespaces_mutex);
 
   std::string error_msg;
-  NativeLoaderNamespace ns;
   bool success = g_namespaces->Create(env,
                                       target_sdk_version,
                                       class_loader,
@@ -622,8 +617,7 @@
                                       is_for_vendor,
                                       library_path,
                                       permitted_path,
-                                      &ns,
-                                      &error_msg);
+                                      &error_msg) != nullptr;
   if (!success) {
     return env->NewStringUTF(error_msg.c_str());
   }
@@ -649,43 +643,24 @@
   }
 
   std::lock_guard<std::mutex> guard(g_namespaces_mutex);
-  NativeLoaderNamespace ns;
+  NativeLoaderNamespace* ns;
 
-  if (!g_namespaces->FindNamespaceByClassLoader(env, class_loader, &ns)) {
+  if ((ns = g_namespaces->FindNamespaceByClassLoader(env, class_loader)) == nullptr) {
     // This is the case where the classloader was not created by ApplicationLoaders
     // In this case we create an isolated not-shared namespace for it.
-    if (!g_namespaces->Create(env,
-                              target_sdk_version,
-                              class_loader,
-                              false /* is_shared */,
-                              false /* is_for_vendor */,
-                              library_path,
-                              nullptr,
-                              &ns,
-                              error_msg)) {
+    if ((ns = g_namespaces->Create(env,
+                                   target_sdk_version,
+                                   class_loader,
+                                   false /* is_shared */,
+                                   false /* is_for_vendor */,
+                                   library_path,
+                                   nullptr,
+                                   error_msg)) == nullptr) {
       return nullptr;
     }
   }
 
-  if (ns.is_android_namespace()) {
-    android_dlextinfo extinfo;
-    extinfo.flags = ANDROID_DLEXT_USE_NAMESPACE;
-    extinfo.library_namespace = ns.get_android_ns();
-
-    void* handle = android_dlopen_ext(path, RTLD_NOW, &extinfo);
-    if (handle == nullptr) {
-      *error_msg = dlerror();
-    }
-    *needs_native_bridge = false;
-    return handle;
-  } else {
-    void* handle = NativeBridgeLoadLibraryExt(path, RTLD_NOW, ns.get_native_bridge_ns());
-    if (handle == nullptr) {
-      *error_msg = NativeBridgeGetError();
-    }
-    *needs_native_bridge = true;
-    return handle;
-  }
+  return OpenNativeLibrary(ns, path, needs_native_bridge, error_msg);
 #else
   UNUSED(env, target_sdk_version, class_loader);
 
@@ -741,18 +716,45 @@
 }
 
 #if defined(__ANDROID__)
+void* OpenNativeLibrary(NativeLoaderNamespace* ns, const char* path, bool* needs_native_bridge,
+                        std::string* error_msg) {
+  if (ns->is_android_namespace()) {
+    android_dlextinfo extinfo;
+    extinfo.flags = ANDROID_DLEXT_USE_NAMESPACE;
+    extinfo.library_namespace = ns->get_android_ns();
+
+    void* handle = android_dlopen_ext(path, RTLD_NOW, &extinfo);
+    if (handle == nullptr) {
+      *error_msg = dlerror();
+    }
+    *needs_native_bridge = false;
+    return handle;
+  } else {
+    void* handle = NativeBridgeLoadLibraryExt(path, RTLD_NOW, ns->get_native_bridge_ns());
+    if (handle == nullptr) {
+      *error_msg = NativeBridgeGetError();
+    }
+    *needs_native_bridge = true;
+    return handle;
+  }
+}
+
 // native_bridge_namespaces are not supported for callers of this function.
 // This function will return nullptr in the case when application is running
 // on native bridge.
 android_namespace_t* FindNamespaceByClassLoader(JNIEnv* env, jobject class_loader) {
   std::lock_guard<std::mutex> guard(g_namespaces_mutex);
-  NativeLoaderNamespace ns;
-  if (g_namespaces->FindNamespaceByClassLoader(env, class_loader, &ns)) {
-    return ns.is_android_namespace() ? ns.get_android_ns() : nullptr;
+  NativeLoaderNamespace* ns = g_namespaces->FindNamespaceByClassLoader(env, class_loader);
+  if (ns != nullptr) {
+    return ns->is_android_namespace() ? ns->get_android_ns() : nullptr;
   }
 
   return nullptr;
 }
+NativeLoaderNamespace* FindNativeLoaderNamespaceByClassLoader(JNIEnv* env, jobject class_loader) {
+  std::lock_guard<std::mutex> guard(g_namespaces_mutex);
+  return g_namespaces->FindNamespaceByClassLoader(env, class_loader);
+}
 #endif
 
 }; //  android namespace