1 /*
2  * Copyright (C) 2018 The Android Open Source Project
3  *
4  * This code is free software; you can redistribute it and/or modify it
5  * under the terms of the GNU General Public License version 2 only, as
6  * published by the Free Software Foundation.  The Android Open Source
7  * Project designates this particular file as subject to the "Classpath"
8  * exception as provided by The Android Open Source Project in the LICENSE
9  * file that accompanied this code.
10  *
11  * This code is distributed in the hope that it will be useful, but WITHOUT
12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14  * version 2 for more details (a copy is included in the LICENSE file that
15  * accompanied this code).
16  *
17  * You should have received a copy of the GNU General Public License version
18  * 2 along with this work; if not, write to the Free Software Foundation,
19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20  */
21 
22 #define LOG_TAG "JniConstants"
23 
24 #include "JniConstants.h"
25 
26 #include <atomic>
27 #include <mutex>
28 
29 #include <log/log.h>
30 #include <nativehelper/ScopedLocalRef.h>
31 
32 namespace {
33 
findClass(JNIEnv * env,const char * name)34 jclass findClass(JNIEnv* env, const char* name) {
35     ScopedLocalRef<jclass> localClass(env, env->FindClass(name));
36     jclass result = reinterpret_cast<jclass>(env->NewGlobalRef(localClass.get()));
37     if (result == NULL) {
38         ALOGE("failed to find class '%s'", name);
39         abort();
40     }
41     return result;
42 }
43 
44 // Mutex protecting static variables
45 static std::mutex g_constants_mutex;
46 
47 // Flag indicating whether cached constants are valid
48 static bool g_constants_valid = false;
49 
50 // Constants
51 jclass g_socket_tagger_class;
52 
53 // EnsureJniConstantsInitialized initializes cache constants. It should be
54 // called before returning a heap object from the cache to ensure cache is
55 // initialized. This pattern is only necessary because if a process finishes one
56 // runtime and starts another then JNI_OnLoad may not be called.
EnsureJniConstantsInitialized(JNIEnv * env)57 void EnsureJniConstantsInitialized(JNIEnv* env) {
58     if (g_constants_valid) {
59         return;
60     }
61 
62     std::lock_guard guard(g_constants_mutex);
63     if (g_constants_valid) {
64         return;
65     }
66 
67     g_socket_tagger_class = findClass(env, "dalvik/system/SocketTagger");
68     g_constants_valid = true;
69 }
70 
71 }  // namespace
72 
Initialize(JNIEnv * env)73 void JniConstants::Initialize(JNIEnv* env) {
74     EnsureJniConstantsInitialized(env);
75 }
76 
Invalidate()77 void JniConstants::Invalidate() {
78     std::lock_guard guard(g_constants_mutex);
79     g_constants_valid = false;
80 }
81 
GetSocketTaggerClass(JNIEnv * env)82 jclass JniConstants::GetSocketTaggerClass(JNIEnv* env) {
83     EnsureJniConstantsInitialized(env);
84     return g_socket_tagger_class;
85 }
86