1 /*
2 * Copyright (C) 2013 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include "JniInvocation.h"
18
19 #include <dlfcn.h>
20 #include <stdlib.h>
21 #include <string.h>
22
23 #include <cstddef>
24
25 #define LOG_TAG "JniInvocation"
26 #include "cutils/log.h"
27
28 #ifdef HAVE_ANDROID_OS
29 #include "cutils/properties.h"
30 #endif
31
32 JniInvocation* JniInvocation::jni_invocation_ = NULL;
33
JniInvocation()34 JniInvocation::JniInvocation() :
35 handle_(NULL),
36 JNI_GetDefaultJavaVMInitArgs_(NULL),
37 JNI_CreateJavaVM_(NULL),
38 JNI_GetCreatedJavaVMs_(NULL) {
39
40 LOG_ALWAYS_FATAL_IF(jni_invocation_ != NULL, "JniInvocation instance already initialized");
41 jni_invocation_ = this;
42 }
43
~JniInvocation()44 JniInvocation::~JniInvocation() {
45 jni_invocation_ = NULL;
46 if (handle_ != NULL) {
47 dlclose(handle_);
48 }
49 }
50
51 #ifdef HAVE_ANDROID_OS
52 static const char* kLibrarySystemProperty = "persist.sys.dalvik.vm.lib.2";
53 static const char* kDebuggableSystemProperty = "ro.debuggable";
54 static const char* kDebuggableFallback = "0"; // Not debuggable.
55 #endif
56 static const char* kLibraryFallback = "libart.so";
57
UNUSED(const T &)58 template<typename T> void UNUSED(const T&) {}
59
GetLibrary(const char * library,char * buffer)60 const char* JniInvocation::GetLibrary(const char* library, char* buffer) {
61 #ifdef HAVE_ANDROID_OS
62 const char* default_library;
63
64 char debuggable[PROPERTY_VALUE_MAX];
65 property_get(kDebuggableSystemProperty, debuggable, kDebuggableFallback);
66
67 if (strcmp(debuggable, "1") != 0) {
68 // Not a debuggable build.
69 // Do not allow arbitrary library. Ignore the library parameter. This
70 // will also ignore the default library, but initialize to fallback
71 // for cleanliness.
72 library = kLibraryFallback;
73 default_library = kLibraryFallback;
74 } else {
75 // Debuggable build.
76 // Accept the library parameter. For the case it is NULL, load the default
77 // library from the system property.
78 if (buffer != NULL) {
79 property_get(kLibrarySystemProperty, buffer, kLibraryFallback);
80 default_library = buffer;
81 } else {
82 // No buffer given, just use default fallback.
83 default_library = kLibraryFallback;
84 }
85 }
86 #else
87 UNUSED(buffer);
88 const char* default_library = kLibraryFallback;
89 #endif
90 if (library == NULL) {
91 library = default_library;
92 }
93
94 return library;
95 }
96
Init(const char * library)97 bool JniInvocation::Init(const char* library) {
98 #ifdef HAVE_ANDROID_OS
99 char buffer[PROPERTY_VALUE_MAX];
100 #else
101 char* buffer = NULL;
102 #endif
103 library = GetLibrary(library, buffer);
104
105 handle_ = dlopen(library, RTLD_NOW);
106 if (handle_ == NULL) {
107 if (strcmp(library, kLibraryFallback) == 0) {
108 // Nothing else to try.
109 ALOGE("Failed to dlopen %s: %s", library, dlerror());
110 return false;
111 }
112 // Note that this is enough to get something like the zygote
113 // running, we can't property_set here to fix this for the future
114 // because we are root and not the system user. See
115 // RuntimeInit.commonInit for where we fix up the property to
116 // avoid future fallbacks. http://b/11463182
117 ALOGW("Falling back from %s to %s after dlopen error: %s",
118 library, kLibraryFallback, dlerror());
119 library = kLibraryFallback;
120 handle_ = dlopen(library, RTLD_NOW);
121 if (handle_ == NULL) {
122 ALOGE("Failed to dlopen %s: %s", library, dlerror());
123 return false;
124 }
125 }
126 if (!FindSymbol(reinterpret_cast<void**>(&JNI_GetDefaultJavaVMInitArgs_),
127 "JNI_GetDefaultJavaVMInitArgs")) {
128 return false;
129 }
130 if (!FindSymbol(reinterpret_cast<void**>(&JNI_CreateJavaVM_),
131 "JNI_CreateJavaVM")) {
132 return false;
133 }
134 if (!FindSymbol(reinterpret_cast<void**>(&JNI_GetCreatedJavaVMs_),
135 "JNI_GetCreatedJavaVMs")) {
136 return false;
137 }
138 return true;
139 }
140
JNI_GetDefaultJavaVMInitArgs(void * vmargs)141 jint JniInvocation::JNI_GetDefaultJavaVMInitArgs(void* vmargs) {
142 return JNI_GetDefaultJavaVMInitArgs_(vmargs);
143 }
144
JNI_CreateJavaVM(JavaVM ** p_vm,JNIEnv ** p_env,void * vm_args)145 jint JniInvocation::JNI_CreateJavaVM(JavaVM** p_vm, JNIEnv** p_env, void* vm_args) {
146 return JNI_CreateJavaVM_(p_vm, p_env, vm_args);
147 }
148
JNI_GetCreatedJavaVMs(JavaVM ** vms,jsize size,jsize * vm_count)149 jint JniInvocation::JNI_GetCreatedJavaVMs(JavaVM** vms, jsize size, jsize* vm_count) {
150 return JNI_GetCreatedJavaVMs_(vms, size, vm_count);
151 }
152
FindSymbol(void ** pointer,const char * symbol)153 bool JniInvocation::FindSymbol(void** pointer, const char* symbol) {
154 *pointer = dlsym(handle_, symbol);
155 if (*pointer == NULL) {
156 ALOGE("Failed to find symbol %s: %s\n", symbol, dlerror());
157 dlclose(handle_);
158 handle_ = NULL;
159 return false;
160 }
161 return true;
162 }
163
GetJniInvocation()164 JniInvocation& JniInvocation::GetJniInvocation() {
165 LOG_ALWAYS_FATAL_IF(jni_invocation_ == NULL,
166 "Failed to create JniInvocation instance before using JNI invocation API");
167 return *jni_invocation_;
168 }
169
JNI_GetDefaultJavaVMInitArgs(void * vm_args)170 extern "C" jint JNI_GetDefaultJavaVMInitArgs(void* vm_args) {
171 return JniInvocation::GetJniInvocation().JNI_GetDefaultJavaVMInitArgs(vm_args);
172 }
173
JNI_CreateJavaVM(JavaVM ** p_vm,JNIEnv ** p_env,void * vm_args)174 extern "C" jint JNI_CreateJavaVM(JavaVM** p_vm, JNIEnv** p_env, void* vm_args) {
175 return JniInvocation::GetJniInvocation().JNI_CreateJavaVM(p_vm, p_env, vm_args);
176 }
177
JNI_GetCreatedJavaVMs(JavaVM ** vms,jsize size,jsize * vm_count)178 extern "C" jint JNI_GetCreatedJavaVMs(JavaVM** vms, jsize size, jsize* vm_count) {
179 return JniInvocation::GetJniInvocation().JNI_GetCreatedJavaVMs(vms, size, vm_count);
180 }
181