diff --git a/app/src/main/cpp/emu_jni.cpp b/app/src/main/cpp/emu_jni.cpp index 2a249438e..c905cf830 100644 --- a/app/src/main/cpp/emu_jni.cpp +++ b/app/src/main/cpp/emu_jni.cpp @@ -71,6 +71,8 @@ extern "C" JNIEXPORT void Java_emu_skyline_EmulationActivity_executeApplication( jstring romUriJstring, jint romType, jint romFd, + jintArray dlcFds, + jint updateFd, jobject settingsInstance, jstring publicAppFilesPathJstring, jstring privateAppFilesPathJstring, @@ -85,6 +87,12 @@ extern "C" JNIEXPORT void Java_emu_skyline_EmulationActivity_executeApplication( auto jvmManager{std::make_shared(env, instance)}; + jsize dlcArrSize = dlcFds != nullptr ? env->GetArrayLength(dlcFds) : 0; + std::vector dlcFdsVector(dlcArrSize); + + if (dlcArrSize > 0) + env->GetIntArrayRegion(dlcFds, 0, dlcArrSize, &dlcFdsVector[0]); + std::shared_ptr settings{std::make_shared(env, settingsInstance)}; skyline::JniString publicAppFilesPath(env, publicAppFilesPathJstring); @@ -121,7 +129,7 @@ extern "C" JNIEXPORT void Java_emu_skyline_EmulationActivity_executeApplication( skyline::Logger::DebugNoPrefix("Launching ROM {}", skyline::JniString(env, romUriJstring)); - os->Execute(romFd, static_cast(romType)); + os->Execute(romFd, dlcFdsVector, updateFd, static_cast(romType)); } catch (std::exception &e) { skyline::Logger::ErrorNoPrefix("An uncaught exception has occurred: {}", e.what()); } catch (const skyline::signal::SignalException &e) { @@ -138,7 +146,18 @@ extern "C" JNIEXPORT void Java_emu_skyline_EmulationActivity_executeApplication( skyline::Logger::Write(skyline::Logger::LogLevel::Info, fmt::format("Emulation has ended in {}ms", std::chrono::duration_cast(end - start).count())); skyline::Logger::EmulationContext.Finalize(); + close(romFd); + + close(updateFd); + + if (dlcArrSize > 0) { + int i = 0; + jint *body = env->GetIntArrayElements(dlcFds, nullptr); + for (i = 0; i < dlcArrSize; i++) + close(body[i]); + } + } extern "C" JNIEXPORT jboolean Java_emu_skyline_EmulationActivity_stopEmulation(JNIEnv *, jobject, jboolean join) { diff --git a/app/src/main/cpp/skyline/common.h b/app/src/main/cpp/skyline/common.h index 37d4ca236..a971fe63c 100644 --- a/app/src/main/cpp/skyline/common.h +++ b/app/src/main/cpp/skyline/common.h @@ -65,6 +65,8 @@ namespace skyline { std::shared_ptr jvm; std::shared_ptr settings; std::shared_ptr loader; + std::vector> dlcLoaders; + std::shared_ptr updateLoader; std::shared_ptr nce; std::shared_ptr process{}; static thread_local inline std::shared_ptr thread{}; //!< The KThread of the thread which accesses this object diff --git a/app/src/main/cpp/skyline/loader/loader.h b/app/src/main/cpp/skyline/loader/loader.h index 1ef1bea9f..9e9528607 100644 --- a/app/src/main/cpp/skyline/loader/loader.h +++ b/app/src/main/cpp/skyline/loader/loader.h @@ -5,6 +5,8 @@ #include #include +#include +#include #include #include "executable.h" @@ -32,6 +34,9 @@ namespace skyline::loader { MissingTitleKey, MissingTitleKek, MissingKeyArea, + + ErrorSparseNCA, + ErrorCompressedNCA, }; /** @@ -85,6 +90,10 @@ namespace skyline::loader { ExecutableLoadInfo LoadExecutable(const std::shared_ptr &process, const DeviceState &state, Executable &executable, size_t offset = 0, const std::string &name = {}, bool dynamicallyLinked = false); std::optional nacp; + std::optional cnmt; + std::optional programNca; //!< The main program NCA within the NSP + std::optional controlNca; //!< The main control NCA within the NSP + std::optional publicNca; std::shared_ptr romFs; virtual ~Loader() = default; diff --git a/app/src/main/cpp/skyline/loader/nsp.cpp b/app/src/main/cpp/skyline/loader/nsp.cpp index 50816ef89..d54e6102a 100644 --- a/app/src/main/cpp/skyline/loader/nsp.cpp +++ b/app/src/main/cpp/skyline/loader/nsp.cpp @@ -5,6 +5,7 @@ #include #include "nca.h" #include "nsp.h" +#include "vfs/patch_manager.h" namespace skyline::loader { static void ExtractTickets(const std::shared_ptr& dir, const std::shared_ptr &keyStore) { @@ -33,12 +34,14 @@ namespace skyline::loader { try { auto nca{vfs::NCA(nsp->OpenFile(entry.name), keyStore)}; - if (nca.contentType == vfs::NcaContentType::Program && nca.romFs != nullptr && nca.exeFs != nullptr) + if (nca.contentType == vfs::NCAContentType::Program && nca.romFs != nullptr && nca.exeFs != nullptr) programNca = std::move(nca); - else if (nca.contentType == vfs::NcaContentType::Control && nca.romFs != nullptr) + else if (nca.contentType == vfs::NCAContentType::Control && nca.romFs != nullptr) controlNca = std::move(nca); - else if (nca.contentType == vfs::NcaContentType::Meta) + else if (nca.contentType == vfs::NCAContentType::Meta) metaNca = std::move(nca); + else if (nca.contentType == vfs::NCAContentType::PublicData) + publicNca = std::move(nca); } catch (const loader_exception &e) { throw loader_exception(e.error); } catch (const std::exception &e) { @@ -59,6 +62,11 @@ namespace skyline::loader { } void *NspLoader::LoadProcessData(const std::shared_ptr &process, const DeviceState &state) { + if (state.updateLoader) { + auto patchManager{std::make_shared()}; + programNca->exeFs = patchManager->PatchExeFS(state, programNca->exeFs); + } + process->npdm = vfs::NPDM(programNca->exeFs->OpenFile("main.npdm")); return NcaLoader::LoadExeFs(this, programNca->exeFs, process, state); }