1414
1515#include " jvm_tooling.h"
1616
17+ #if defined(_ANDROID)
18+ #include < dlfcn.h>
19+ #endif
20+
1721#include < cstdlib>
1822#include < fstream>
1923#include < iostream>
@@ -120,20 +124,74 @@ std::vector<std::string> splitEscaped(const std::string &str) {
120124
121125namespace jazzer {
122126
123- JVM::JVM (const std::string &executable_path) {
127+ #if defined(_ANDROID)
128+ typedef jint (*JNI_CreateJavaVM_t)(JavaVM **, JNIEnv **, void *);
129+ JNI_CreateJavaVM_t LoadAndroidVMLibs () {
130+ std::cout << " Loading Android libraries" << std::endl;
131+
132+ void *art_so = nullptr ;
133+ art_so = dlopen (" libnativehelper.so" , RTLD_NOW);
134+
135+ if (art_so == nullptr ) {
136+ std::cerr << " Could not find ART library" << std::endl;
137+ exit (1 );
138+ }
139+
140+ typedef void *(*JniInvocationCreate_t)();
141+ JniInvocationCreate_t JniInvocationCreate =
142+ reinterpret_cast <JniInvocationCreate_t>(
143+ dlsym (art_so, " JniInvocationCreate" ));
144+ if (JniInvocationCreate == nullptr ) {
145+ std::cout << " JniInvocationCreate is null" << std::endl;
146+ exit (1 );
147+ }
148+
149+ void *impl = JniInvocationCreate ();
150+ typedef bool (*JniInvocationInit_t)(void *, const char *);
151+ JniInvocationInit_t JniInvocationInit =
152+ reinterpret_cast <JniInvocationInit_t>(dlsym (art_so, " JniInvocationInit" ));
153+ if (JniInvocationInit == nullptr ) {
154+ std::cout << " JniInvocationInit is null" << std::endl;
155+ exit (1 );
156+ }
157+
158+ JniInvocationInit (impl, nullptr );
159+
160+ constexpr char create_jvm_symbol[] = " JNI_CreateJavaVM" ;
161+ typedef jint (*JNI_CreateJavaVM_t)(JavaVM **, JNIEnv **, void *);
162+ JNI_CreateJavaVM_t JNI_CreateArtVM =
163+ reinterpret_cast <JNI_CreateJavaVM_t>(dlsym (art_so, create_jvm_symbol));
164+ if (JNI_CreateArtVM == nullptr ) {
165+ std::cout << " JNI_CreateJavaVM is null" << std::endl;
166+ exit (1 );
167+ }
168+
169+ return JNI_CreateArtVM;
170+ }
171+ #endif
172+
173+ std::string GetClassPath (const std::string &executable_path) {
124174 // combine class path from command line flags and JAVA_FUZZER_CLASSPATH env
125175 // variable
126176 std::string class_path = absl::StrFormat (" -Djava.class.path=%s" , FLAGS_cp);
127177 const auto class_path_from_env = std::getenv (" JAVA_FUZZER_CLASSPATH" );
128178 if (class_path_from_env) {
129179 class_path += absl::StrCat (ARG_SEPARATOR, class_path_from_env);
130180 }
181+
131182 class_path +=
132183 absl::StrCat (ARG_SEPARATOR, getInstrumentorAgentPath (executable_path));
184+ return class_path;
185+ }
186+
187+ JVM::JVM (const std::string &executable_path) {
188+ std::string class_path = GetClassPath (executable_path);
133189
134190 std::vector<JavaVMOption> options;
135191 options.push_back (
136192 JavaVMOption{.optionString = const_cast <char *>(class_path.c_str ())});
193+
194+ #if !defined(_ANDROID)
137195 // Set the maximum heap size to a value that is slightly smaller than
138196 // libFuzzer's default rss_limit_mb. This prevents erroneous oom reports.
139197 options.push_back (JavaVMOption{.optionString = (char *)" -Xmx1800m" });
@@ -148,44 +206,66 @@ JVM::JVM(const std::string &executable_path) {
148206 JavaVMOption{.optionString = (char *)" -XX:+IgnoreUnrecognizedVMOptions" });
149207 options.push_back (
150208 JavaVMOption{.optionString = (char *)" -XX:+CriticalJNINatives" });
209+ #endif
151210
152- // Add additional JVM options set through JAVA_OPTS.
153211 std::vector<std::string> java_opts_args;
154212 const char *java_opts = std::getenv (" JAVA_OPTS" );
155213 if (java_opts != nullptr ) {
156214 // Mimic the behavior of the JVM when it sees JAVA_TOOL_OPTIONS.
157215 std::cerr << " Picked up JAVA_OPTS: " << java_opts << std::endl;
216+
158217 java_opts_args = absl::StrSplit (java_opts, ' ' );
159218 for (const std::string &java_opt : java_opts_args) {
160219 options.push_back (
161220 JavaVMOption{.optionString = const_cast <char *>(java_opt.c_str ())});
162221 }
163222 }
164223
165- // add additional jvm options set through command line flags
224+ // Add additional jvm options set through command line flags.
225+ // Keep the vectors in scope as they contain the strings backing the C strings
226+ // added to options.
166227 std::vector<std::string> jvm_args;
167228 if (!FLAGS_jvm_args.empty ()) {
168229 jvm_args = splitEscaped (FLAGS_jvm_args);
230+ for (const auto &arg : jvm_args) {
231+ options.push_back (
232+ JavaVMOption{.optionString = const_cast <char *>(arg.c_str ())});
233+ }
169234 }
170- for (const auto &arg : jvm_args) {
171- options.push_back (
172- JavaVMOption{.optionString = const_cast <char *>(arg.c_str ())});
173- }
235+
174236 std::vector<std::string> additional_jvm_args;
175237 if (!FLAGS_additional_jvm_args.empty ()) {
176238 additional_jvm_args = splitEscaped (FLAGS_additional_jvm_args);
239+ for (const auto &arg : additional_jvm_args) {
240+ options.push_back (
241+ JavaVMOption{.optionString = const_cast <char *>(arg.c_str ())});
242+ }
177243 }
178- for (const auto &arg : additional_jvm_args) {
179- options.push_back (
180- JavaVMOption{.optionString = const_cast <char *>(arg.c_str ())});
181- }
182244
183- JavaVMInitArgs jvm_init_args = {.version = JNI_VERSION_1_8,
245+ #if !defined(_ANDROID)
246+ jint jni_version = JNI_VERSION_1_8;
247+ #else
248+ jint jni_version = JNI_VERSION_1_6;
249+ #endif
250+
251+ JavaVMInitArgs jvm_init_args = {.version = jni_version,
184252 .nOptions = (int )options.size (),
185253 .options = options.data (),
186254 .ignoreUnrecognized = JNI_FALSE};
187255
188- auto ret = JNI_CreateJavaVM (&jvm_, (void **)&env_, &jvm_init_args);
256+ #if !defined(_ANDROID)
257+ int ret = JNI_CreateJavaVM (&jvm_, (void **)&env_, &jvm_init_args);
258+ #else
259+ JNI_CreateJavaVM_t CreateArtVM = LoadAndroidVMLibs ();
260+ if (CreateArtVM == nullptr ) {
261+ std::cerr << " JNI_CreateJavaVM for Android not found" << std::endl;
262+ exit (1 );
263+ }
264+
265+ std::cout << " Starting Art VM" << std::endl;
266+ int ret = CreateArtVM (&jvm_, (JNIEnv_ **)&env_, &jvm_init_args);
267+ #endif
268+
189269 if (ret != JNI_OK) {
190270 throw std::runtime_error (
191271 absl::StrFormat (" JNI_CreateJavaVM returned code %d" , ret));
0 commit comments