Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 0be8feb3 authored by Treehugger Robot's avatar Treehugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Properly manage JniStringCache lifecycle and clear on unload." into main

parents e005af39 b74e22cb
Loading
Loading
Loading
Loading
+5 −0
Original line number Original line Diff line number Diff line
@@ -35,6 +35,7 @@
#include <dlfcn.h>
#include <dlfcn.h>
#include <nativehelper/JNIHelp.h>
#include <nativehelper/JNIHelp.h>
#include <nativehelper/JniInvocation.h>
#include <nativehelper/JniInvocation.h>
#include "com_android_internal_os_JniStringCache.h"
#include <server_configurable_flags/get_flags.h>
#include <server_configurable_flags/get_flags.h>
#include <signal.h>
#include <signal.h>
#include <stdio.h>
#include <stdio.h>
@@ -109,6 +110,10 @@ extern int register_android_media_ToneGenerator(JNIEnv *env);
extern int register_android_media_audio_common_AidlConversion(JNIEnv* env);
extern int register_android_media_audio_common_AidlConversion(JNIEnv* env);
extern int register_android_media_midi(JNIEnv *env);
extern int register_android_media_midi(JNIEnv *env);


extern "C" JNIEXPORT void JNICALL JNI_OnUnload(JavaVM* vm, void* reserved) {
    JniStringCache::Unload(vm);
}

namespace android {
namespace android {


/*
/*
+25 −4
Original line number Original line Diff line number Diff line
@@ -20,10 +20,12 @@
#include <android_runtime/AndroidRuntime.h>
#include <android_runtime/AndroidRuntime.h>


#include <atomic>
#include <atomic>
#include <mutex>


namespace android {
namespace android {


namespace {
namespace {

template <typename TChar>
template <typename TChar>
uint32_t computeHash(const TChar* s, size_t len) {
uint32_t computeHash(const TChar* s, size_t len) {
    uint32_t h = 0;
    uint32_t h = 0;
@@ -65,11 +67,14 @@ bool StringsAreEqual(JNIEnv* env, jstring jstr, const char* chars, size_t len) {
    return result;
    return result;
}
}


JniStringCache* gInstance = nullptr;
std::once_flag gInstanceFlag;

} // namespace
} // namespace


JniStringCache& JniStringCache::getInstance() {
JniStringCache& JniStringCache::getInstance() {
    static JniStringCache instance;
    std::call_once(gInstanceFlag, []() { gInstance = new JniStringCache(); });
    return instance;
    return *gInstance;
}
}


JniStringCache::JniStringCache() : mHits(0), mMisses(0), mEvictions(0), mSkips(0) {}
JniStringCache::JniStringCache() : mHits(0), mMisses(0), mEvictions(0), mSkips(0) {}
@@ -261,12 +266,14 @@ size_t JniStringCache::skips() const {
}
}


void JniStringCache::clear() {
void JniStringCache::clear() {
    JNIEnv* env = AndroidRuntime::getJNIEnv();
    clear(AndroidRuntime::getJNIEnv());
}

void JniStringCache::clear(JNIEnv* env) {
    if (env == nullptr) {
    if (env == nullptr) {
        DCHECK(false) << "JNIEnv is null, can't clear cache";
        DCHECK(false) << "JNIEnv is null, can't clear cache";
        return;
        return;
    }
    }

    auto clear_cache = [&](std::atomic<CacheEntry>* cache) {
    auto clear_cache = [&](std::atomic<CacheEntry>* cache) {
        for (size_t i = 0; i < kCacheSize; ++i) {
        for (size_t i = 0; i < kCacheSize; ++i) {
            std::atomic<CacheEntry>& slot = cache[i];
            std::atomic<CacheEntry>& slot = cache[i];
@@ -306,6 +313,20 @@ void JniStringCache::clear() {
    clear_cache(mUtf8Cache);
    clear_cache(mUtf8Cache);
}
}


void JniStringCache::Unload(JavaVM* vm) {
    if (gInstance == nullptr) {
        return;
    }

    JNIEnv* env = nullptr;
    if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) == JNI_OK) {
        gInstance->clear(env);
    }

    delete gInstance;
    gInstance = nullptr;
}

static jlong com_android_internal_os_JniStringCache_nativeHits() {
static jlong com_android_internal_os_JniStringCache_nativeHits() {
    return static_cast<jlong>(JniStringCache::getInstance().hits());
    return static_cast<jlong>(JniStringCache::getInstance().hits());
}
}
+4 −0
Original line number Original line Diff line number Diff line
@@ -41,6 +41,9 @@ public:
    // Global instance to use in order to maximize cache hits.
    // Global instance to use in order to maximize cache hits.
    static JniStringCache& getInstance();
    static JniStringCache& getInstance();


    // Clears all global references held by the cache.
    static void Unload(JavaVM* vm);

    JniStringCache();
    JniStringCache();
    ~JniStringCache();
    ~JniStringCache();


@@ -67,6 +70,7 @@ public:
    // Under concurrent usage, some entries may not be cleared.
    // Under concurrent usage, some entries may not be cleared.
    // Use this for instance to trim memory usage if needed.
    // Use this for instance to trim memory usage if needed.
    void clear();
    void clear();
    void clear(JNIEnv* env);


private:
private:
    struct CacheEntry {
    struct CacheEntry {