in app/src/util_android.cc [1588:1702]
jclass FindClassInFiles(
JNIEnv* env, jobject activity_object,
const std::vector<internal::EmbeddedFile>& embedded_files,
const char* class_name) {
if (!embedded_files.size()) {
return nullptr;
}
jobject cache_dir = env->CallObjectMethod(
activity_object, activity::GetMethodId(activity::kGetCacheDir));
CheckAndClearJniExceptions(env);
jobject cache_dir_path_jstring = env->CallObjectMethod(
cache_dir, file::GetMethodId(file::kGetAbsolutePath));
CheckAndClearJniExceptions(env);
std::string cache_dir_path =
firebase::util::JniStringToString(env, cache_dir_path_jstring);
#if defined(FIREBASE_ANDROID_FOR_DESKTOP)
static const char kPathSeparator = '/';
jobject cache_uri =
env->CallObjectMethod(cache_dir, file::GetMethodId(file::kToUri));
CheckAndClearJniExceptions(env);
env->DeleteLocalRef(cache_dir);
jobject cache_url =
env->CallObjectMethod(cache_uri, java_uri::GetMethodId(java_uri::kToUrl));
CheckAndClearJniExceptions(env);
env->DeleteLocalRef(cache_uri);
jobjectArray url_path_array =
env->NewObjectArray(embedded_files.size(), url::GetClass(), nullptr);
for (int i = 0; i < embedded_files.size(); ++i) {
jstring embedded_file_string = env->NewStringUTF(embedded_files[i].name);
jobject jar_url =
env->NewObject(url::GetClass(), url::GetMethodId(url::kConstructor),
cache_url, embedded_file_string);
env->SetObjectArrayElement(url_path_array, i, jar_url);
env->DeleteLocalRef(jar_url);
env->DeleteLocalRef(embedded_file_string);
}
env->DeleteLocalRef(cache_url);
jobject class_loader_obj = env->NewObject(
url_class_loader::GetClass(),
url_class_loader::GetMethodId(url_class_loader::kConstructor),
url_path_array, GetParentLoader());
env->DeleteLocalRef(url_path_array);
std::string class_name_str(class_name);
std::replace(class_name_str.begin(), class_name_str.end(), kPathSeparator,
'.');
LogDebug("Load class %s (a.k.a. %s)", class_name_str.c_str(), class_name);
jstring class_name_object = env->NewStringUTF(class_name_str.c_str());
jclass loaded_class = static_cast<jclass>(env->CallObjectMethod(
class_loader_obj,
url_class_loader::GetMethodId(url_class_loader::kLoadClass),
class_name_object));
CheckAndClearJniExceptions(env);
#else // defined(FIREBASE_ANDROID_FOR_DESKTOP)
static const char kPathSeparator = '/';
static const char kDexPathSeparator = ':';
// Older versions of Android don't have GetCodeCacheDir, so fall back to
// GetCacheDir.
const jmethodID get_code_cache_dir_method_id =
activity::GetMethodId(activity::kGetCodeCacheDir) != 0
? activity::GetMethodId(activity::kGetCodeCacheDir)
: activity::GetMethodId(activity::kGetCacheDir);
jobject code_cache_dir =
env->CallObjectMethod(activity_object, get_code_cache_dir_method_id);
CheckAndClearJniExceptions(env);
jobject code_cache_dir_path = env->CallObjectMethod(
code_cache_dir, file::GetMethodId(file::kGetAbsolutePath));
CheckAndClearJniExceptions(env);
env->DeleteLocalRef(code_cache_dir);
env->DeleteLocalRef(cache_dir);
std::string dex_path;
for (std::vector<internal::EmbeddedFile>::const_iterator it =
embedded_files.begin();
it != embedded_files.end(); ++it) {
dex_path += cache_dir_path + kPathSeparator + std::string(it->name);
dex_path.push_back(kDexPathSeparator);
}
dex_path.pop_back();
LogDebug("Set class path to %s", dex_path.c_str());
jstring dex_path_string = env->NewStringUTF(dex_path.c_str());
jobject class_loader_obj = env->NewObject(
dex_class_loader::GetClass(),
dex_class_loader::GetMethodId(dex_class_loader::kConstructor),
dex_path_string, code_cache_dir_path, nullptr, GetParentLoader());
env->DeleteLocalRef(code_cache_dir_path);
env->DeleteLocalRef(dex_path_string);
LogDebug("Load class %s", class_name);
jstring class_name_object = env->NewStringUTF(class_name);
jclass loaded_class = static_cast<jclass>(env->CallObjectMethod(
class_loader_obj,
dex_class_loader::GetMethodId(dex_class_loader::kLoadClass),
class_name_object));
CheckAndClearJniExceptions(env);
#endif // defined(FIREBASE_ANDROID_FOR_DESKTOP)
if (!env->ExceptionCheck()) {
LogDebug("%s loaded.", class_name);
AddClassLoader(env, class_loader_obj);
} else {
env->ExceptionClear();
LogDebug("%s *not* loaded", class_name);
env->DeleteLocalRef(loaded_class);
env->DeleteLocalRef(class_loader_obj);
}
env->DeleteLocalRef(class_name_object);
return loaded_class;
}