blob: f4dd24e2926d08f212bce607207bc1a00d9fc982 [file] [log] [blame]
Brian Carlstromb2acfa22013-06-19 15:09:28 -07001/*
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>
Brian Carlstromfeeb36c2013-10-31 15:18:56 -070021#include <string.h>
Brian Carlstromb2acfa22013-06-19 15:09:28 -070022
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
32JniInvocation* JniInvocation::jni_invocation_ = NULL;
33
34JniInvocation::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
44JniInvocation::~JniInvocation() {
45 jni_invocation_ = NULL;
46 if (handle_ != NULL) {
47 dlclose(handle_);
48 }
49}
50
Brian Carlstromfeeb36c2013-10-31 15:18:56 -070051#ifdef HAVE_ANDROID_OS
Brian Carlstrom3a4f0c32014-05-28 14:31:47 -070052static const char* kLibrarySystemProperty = "persist.sys.dalvik.vm.lib.2";
Andreas Gampe5f4f4aa2014-08-19 16:57:38 -070053static const char* kDebuggableSystemProperty = "ro.debuggable";
54static const char* kDebuggableFallback = "0"; // Not debuggable.
Brian Carlstromfeeb36c2013-10-31 15:18:56 -070055#endif
Narayan Kamath8c4708c2014-05-12 16:49:11 +010056static const char* kLibraryFallback = "libart.so";
Brian Carlstromfeeb36c2013-10-31 15:18:56 -070057
Andreas Gampe5f4f4aa2014-08-19 16:57:38 -070058const char* JniInvocation::GetLibrary(const char* library) {
Brian Carlstromb2acfa22013-06-19 15:09:28 -070059#ifdef HAVE_ANDROID_OS
60 char default_library[PROPERTY_VALUE_MAX];
Andreas Gampe5f4f4aa2014-08-19 16:57:38 -070061
62 char debuggable[PROPERTY_VALUE_MAX];
63 property_get(kDebuggableSystemProperty, debuggable, kDebuggableFallback);
64
65 if (strcmp(debuggable, "1") != 0) {
66 // Not a debuggable build.
67 // Do not allow arbitrary library. Ignore the library parameter. This
68 // will also ignore the default library, but initialize to empty string
69 // for cleanliness.
70 library = kLibraryFallback;
71 default_library[0] = 0;
72 } else {
73 // Debuggable build.
74 // Accept the library parameter. For the case it is NULL, load the default
75 // library from the system property.
76 property_get(kLibrarySystemProperty, default_library, kLibraryFallback);
77 }
Brian Carlstromb2acfa22013-06-19 15:09:28 -070078#else
Brian Carlstromfeeb36c2013-10-31 15:18:56 -070079 const char* default_library = kLibraryFallback;
Brian Carlstromb2acfa22013-06-19 15:09:28 -070080#endif
81 if (library == NULL) {
82 library = default_library;
83 }
84
Andreas Gampe5f4f4aa2014-08-19 16:57:38 -070085 return library;
86}
87
88bool JniInvocation::Init(const char* library) {
89 library = GetLibrary(library);
90
Brian Carlstromb2acfa22013-06-19 15:09:28 -070091 handle_ = dlopen(library, RTLD_NOW);
92 if (handle_ == NULL) {
Brian Carlstromfeeb36c2013-10-31 15:18:56 -070093 if (strcmp(library, kLibraryFallback) == 0) {
94 // Nothing else to try.
95 ALOGE("Failed to dlopen %s: %s", library, dlerror());
96 return false;
97 }
98 // Note that this is enough to get something like the zygote
99 // running, we can't property_set here to fix this for the future
100 // because we are root and not the system user. See
101 // RuntimeInit.commonInit for where we fix up the property to
102 // avoid future fallbacks. http://b/11463182
103 ALOGW("Falling back from %s to %s after dlopen error: %s",
104 library, kLibraryFallback, dlerror());
105 library = kLibraryFallback;
106 handle_ = dlopen(library, RTLD_NOW);
107 if (handle_ == NULL) {
108 ALOGE("Failed to dlopen %s: %s", library, dlerror());
109 return false;
110 }
Brian Carlstromb2acfa22013-06-19 15:09:28 -0700111 }
112 if (!FindSymbol(reinterpret_cast<void**>(&JNI_GetDefaultJavaVMInitArgs_),
113 "JNI_GetDefaultJavaVMInitArgs")) {
114 return false;
115 }
116 if (!FindSymbol(reinterpret_cast<void**>(&JNI_CreateJavaVM_),
117 "JNI_CreateJavaVM")) {
118 return false;
119 }
120 if (!FindSymbol(reinterpret_cast<void**>(&JNI_GetCreatedJavaVMs_),
121 "JNI_GetCreatedJavaVMs")) {
122 return false;
123 }
124 return true;
125}
126
127jint JniInvocation::JNI_GetDefaultJavaVMInitArgs(void* vmargs) {
128 return JNI_GetDefaultJavaVMInitArgs_(vmargs);
129}
130
131jint JniInvocation::JNI_CreateJavaVM(JavaVM** p_vm, JNIEnv** p_env, void* vm_args) {
132 return JNI_CreateJavaVM_(p_vm, p_env, vm_args);
133}
134
135jint JniInvocation::JNI_GetCreatedJavaVMs(JavaVM** vms, jsize size, jsize* vm_count) {
136 return JNI_GetCreatedJavaVMs_(vms, size, vm_count);
137}
138
139bool JniInvocation::FindSymbol(void** pointer, const char* symbol) {
140 *pointer = dlsym(handle_, symbol);
141 if (*pointer == NULL) {
142 ALOGE("Failed to find symbol %s: %s\n", symbol, dlerror());
143 dlclose(handle_);
144 handle_ = NULL;
145 return false;
146 }
147 return true;
148}
149
150JniInvocation& JniInvocation::GetJniInvocation() {
151 LOG_ALWAYS_FATAL_IF(jni_invocation_ == NULL,
152 "Failed to create JniInvocation instance before using JNI invocation API");
153 return *jni_invocation_;
154}
155
156extern "C" jint JNI_GetDefaultJavaVMInitArgs(void* vm_args) {
157 return JniInvocation::GetJniInvocation().JNI_GetDefaultJavaVMInitArgs(vm_args);
158}
159
160extern "C" jint JNI_CreateJavaVM(JavaVM** p_vm, JNIEnv** p_env, void* vm_args) {
161 return JniInvocation::GetJniInvocation().JNI_CreateJavaVM(p_vm, p_env, vm_args);
162}
163
164extern "C" jint JNI_GetCreatedJavaVMs(JavaVM** vms, jsize size, jsize* vm_count) {
165 return JniInvocation::GetJniInvocation().JNI_GetCreatedJavaVMs(vms, size, vm_count);
166}