diff --git a/android/PowderActivity.template.java b/android/PowderActivity.template.java index 5fd208cc3..c30ffc528 100644 --- a/android/PowderActivity.template.java +++ b/android/PowderActivity.template.java @@ -10,7 +10,7 @@ import java.util.Base64; public class PowderActivity extends SDLActivity { - public static String getCertificateBundle() + public String getCertificateBundle() { String allPems = ""; try { @@ -39,4 +39,9 @@ public class PowderActivity extends SDLActivity } return allPems; } + + public String getDefaultDdir() + { + return getExternalFilesDir(null).getAbsolutePath(); + } } diff --git a/src/client/http/requestmanager/AndroidCertProvider.cpp b/src/client/http/requestmanager/AndroidCertProvider.cpp index 432045a0d..7c4e2986c 100644 --- a/src/client/http/requestmanager/AndroidCertProvider.cpp +++ b/src/client/http/requestmanager/AndroidCertProvider.cpp @@ -1,84 +1,34 @@ #include "CurlError.h" -#include "common/String.h" +#include "common/platform/Android.h" #include "Config.h" #include -#include -#include #include -static jclass FindClass(JNIEnv *env, const char *name) -{ - jobject nativeActivity = (jobject)SDL_AndroidGetActivity(); if (!nativeActivity) return NULL; - jclass acl = env->GetObjectClass(nativeActivity); if (!acl ) return NULL; - jmethodID getClassLoader = env->GetMethodID(acl, "getClassLoader", "()Ljava/lang/ClassLoader;"); if (!getClassLoader) return NULL; - jobject cls = env->CallObjectMethod(nativeActivity, getClassLoader); if (!cls ) return NULL; - jclass classLoader = env->FindClass("java/lang/ClassLoader"); if (!classLoader ) return NULL; - jmethodID findClass = env->GetMethodID(classLoader, "loadClass", "(Ljava/lang/String;)Ljava/lang/Class;"); if (!findClass ) return NULL; - jstring strClassName = env->NewStringUTF(name); if (!strClassName ) return NULL; - jclass clazz = (jclass)(env->CallObjectMethod(cls, findClass, strClassName)); - env->DeleteLocalRef(strClassName); - return clazz; -} - namespace http { void UseSystemCertProvider(CURL *easy) { struct DoOnce { - ByteString allPems; - - void InitPem() - { - auto die = [](ByteString message) { - __android_log_print(ANDROID_LOG_ERROR, "AndroidCertProvider", "%s", ("failed to enumerate system certificates: " + message).c_str()); - }; - auto *env = (JNIEnv *)SDL_AndroidGetJNIEnv(); - if (!env) - { - return die("SDL_AndroidGetJNIEnv failed"); - } - jclass mPowderActivity = FindClass(env, ByteString::Build(APPID, ".PowderActivity").c_str()); - if (!mPowderActivity) - { - return die("FindClass failed"); - } - jmethodID midGetCertificateBundle = env->GetStaticMethodID(mPowderActivity, "getCertificateBundle", "()Ljava/lang/String;"); - if (!midGetCertificateBundle) - { - return die("GetStaticMethodID failed"); - } - jstring str = (jstring)env->CallStaticObjectMethod(mPowderActivity, midGetCertificateBundle); - if (!str) - { - return die("getCertificateBundle failed"); - } - const char *utf = env->GetStringUTFChars(str, 0); - if (utf) - { - allPems = utf; - env->ReleaseStringUTFChars(str, utf); - } - else - { - __android_log_print(ANDROID_LOG_ERROR, "AndroidCertProvider", "out of memory???"); - } - env->DeleteLocalRef(str); - __android_log_print(ANDROID_LOG_ERROR, "AndroidCertProvider", "certificate bundle loaded"); - } + ByteString certificateBundle; DoOnce() { - InitPem(); + auto certificateBundleOpt = Platform::CallActivityStringFunc("getCertificateBundle"); + if (certificateBundleOpt) + { + certificateBundle = *certificateBundleOpt; + __android_log_print(ANDROID_LOG_ERROR, APPID, "certificate bundle loaded"); + } } }; static DoOnce doOnce; - if (doOnce.allPems.size()) + if (doOnce.certificateBundle.size()) { curl_blob blob; - blob.data = doOnce.allPems.data(); - blob.len = doOnce.allPems.size(); + blob.data = doOnce.certificateBundle.data(); + blob.len = doOnce.certificateBundle.size(); blob.flags = CURL_BLOB_COPY; HandleCURLcode(curl_easy_setopt(easy, CURLOPT_CAINFO_BLOB, &blob)); } diff --git a/src/common/platform/Android.cpp b/src/common/platform/Android.cpp index d29c4d7f9..3844f176f 100644 --- a/src/common/platform/Android.cpp +++ b/src/common/platform/Android.cpp @@ -1,5 +1,11 @@ #include "Platform.h" +#include "Android.h" +#include "common/Defer.h" +#include "Config.h" #include +#include +#include +#include namespace Platform { @@ -28,4 +34,58 @@ bool CanUpdate() void SetupCrt() { } + +std::optional CallActivityStringFunc(const char *funcName) +{ + ByteString result; + struct CheckFailed : public std::runtime_error + { + using runtime_error::runtime_error; + }; + try + { + auto CHECK = [](auto thing, const char *what) { + if (!thing) + { + throw CheckFailed(what); + } + return thing; + }; +#define CHECK(a) CHECK(a, #a) + auto *env = CHECK((JNIEnv *)SDL_AndroidGetJNIEnv()); + auto activityInst = CHECK((jobject)SDL_AndroidGetActivity()); + auto activityCls = CHECK(env->GetObjectClass(activityInst)); + auto getClassLoaderMth = CHECK(env->GetMethodID(activityCls, "getClassLoader", "()Ljava/lang/ClassLoader;")); + auto classLoaderInst = CHECK(env->CallObjectMethod(activityInst, getClassLoaderMth)); + auto classLoaderCls = CHECK(env->FindClass("java/lang/ClassLoader")); + auto findClassMth = CHECK(env->GetMethodID(classLoaderCls, "loadClass", "(Ljava/lang/String;)Ljava/lang/Class;")); + auto strClassName = CHECK(env->NewStringUTF(ByteString::Build(APPID, ".PowderActivity").c_str())); + Defer deleteStrClassName([env, strClassName]() { env->DeleteLocalRef(strClassName); }); + auto mPowderActivity = CHECK((jclass)(env->CallObjectMethod(classLoaderInst, findClassMth, strClassName))); + auto funcMth = CHECK(env->GetMethodID(mPowderActivity, funcName, "()Ljava/lang/String;")); + auto resultRef = CHECK((jstring)env->CallObjectMethod(activityInst, funcMth)); + Defer deleteStr([env, resultRef]() { env->DeleteLocalRef(resultRef); }); + auto *resultBytes = CHECK(env->GetStringUTFChars(resultRef, 0)); + Defer deleteUtf([env, resultRef, resultBytes]() { env->ReleaseStringUTFChars(resultRef, resultBytes); }); + result = resultBytes; + } + catch (const CheckFailed &ex) + { + __android_log_print(ANDROID_LOG_ERROR, APPID, "CallActivityStringFunc/%s failed: %s", funcName, ex.what()); + return std::nullopt; + } +#undef CHECK + return result; +} + +ByteString DefaultDdir() +{ + auto result = CallActivityStringFunc("getDefaultDdir"); + if (result) + { + __android_log_print(ANDROID_LOG_ERROR, APPID, "DefaultDdir succeeded, data dir is %s", result->c_str()); + return *result; + } + return ""; +} } diff --git a/src/common/platform/Android.h b/src/common/platform/Android.h new file mode 100644 index 000000000..a639d9d2a --- /dev/null +++ b/src/common/platform/Android.h @@ -0,0 +1,8 @@ +#pragma once +#include "common/String.h" +#include + +namespace Platform +{ + std::optional CallActivityStringFunc(const char *funcName); +} diff --git a/src/common/platform/meson.build b/src/common/platform/meson.build index 5dc9d1787..f96dea014 100644 --- a/src/common/platform/meson.build +++ b/src/common/platform/meson.build @@ -42,7 +42,6 @@ elif host_platform == 'android' ) powder_files += files( 'MainCommon.cpp', - 'DdirCommon.cpp', ) elif host_platform == 'emscripten' use_bluescreen = false