Move Skyline internal files to external directory

Any Skyline files that should have been user-accessible were moved from `/data/data/skyline.emu/files` to `/sdcard/Android/data/skyline.emu/files` as the former directory is entirely private and cannot be accessed without either adb or root. This made retrieving certain data such as saves or loading custom driver shared objects extremely hard to do while this can be trivially done now.
This commit is contained in:
PixelyIon 2022-04-06 11:18:26 +05:30
parent e5e20f39c9
commit b45437b78b
12 changed files with 47 additions and 27 deletions

View File

@ -62,7 +62,7 @@ extern "C" JNIEXPORT void Java_emu_skyline_SkylineApplication_initializeLog(
) { ) {
std::string appFilesPath{env->GetStringUTFChars(appFilesPathJstring, nullptr)}; std::string appFilesPath{env->GetStringUTFChars(appFilesPathJstring, nullptr)};
skyline::Logger::configLevel = static_cast<skyline::Logger::LogLevel>(logLevel); skyline::Logger::configLevel = static_cast<skyline::Logger::LogLevel>(logLevel);
skyline::Logger::LoaderContext.Initialize(appFilesPath + "loader.sklog"); skyline::Logger::LoaderContext.Initialize(appFilesPath + "logs/loader.sklog");
} }
extern "C" JNIEXPORT void Java_emu_skyline_EmulationActivity_executeApplication( extern "C" JNIEXPORT void Java_emu_skyline_EmulationActivity_executeApplication(
@ -73,7 +73,8 @@ extern "C" JNIEXPORT void Java_emu_skyline_EmulationActivity_executeApplication(
jint romFd, jint romFd,
jint preferenceFd, jint preferenceFd,
jint systemLanguage, jint systemLanguage,
jstring appFilesPathJstring, jstring publicAppFilesPathJstring,
jstring privateAppFilesPathJstring,
jstring nativeLibraryPathJstring, jstring nativeLibraryPathJstring,
jobject assetManager jobject assetManager
) { ) {
@ -87,8 +88,8 @@ extern "C" JNIEXPORT void Java_emu_skyline_EmulationActivity_executeApplication(
auto settings{std::make_shared<skyline::Settings>(preferenceFd)}; auto settings{std::make_shared<skyline::Settings>(preferenceFd)};
close(preferenceFd); close(preferenceFd);
skyline::JniString appFilesPath(env, appFilesPathJstring); skyline::JniString publicAppFilesPath(env, publicAppFilesPathJstring);
skyline::Logger::EmulationContext.Initialize(appFilesPath + "emulation.sklog"); skyline::Logger::EmulationContext.Initialize(publicAppFilesPath + "logs/emulation.sklog");
auto start{std::chrono::steady_clock::now()}; auto start{std::chrono::steady_clock::now()};
@ -100,11 +101,13 @@ extern "C" JNIEXPORT void Java_emu_skyline_EmulationActivity_executeApplication(
try { try {
skyline::JniString nativeLibraryPath(env, nativeLibraryPathJstring); skyline::JniString nativeLibraryPath(env, nativeLibraryPathJstring);
skyline::JniString privateAppFilesPath{env, privateAppFilesPathJstring};
auto os{std::make_shared<skyline::kernel::OS>( auto os{std::make_shared<skyline::kernel::OS>(
jvmManager, jvmManager,
settings, settings,
appFilesPath, publicAppFilesPath,
privateAppFilesPath,
nativeLibraryPath, nativeLibraryPath,
GetTimeZoneName(), GetTimeZoneName(),
static_cast<skyline::language::SystemLanguage>(systemLanguage), static_cast<skyline::language::SystemLanguage>(systemLanguage),

View File

@ -218,7 +218,7 @@ namespace skyline::gpu {
ADRENOTOOLS_DRIVER_CUSTOM, ADRENOTOOLS_DRIVER_CUSTOM,
nullptr, // We require Android 10 so don't need to supply nullptr, // We require Android 10 so don't need to supply
state.os->nativeLibraryPath.c_str(), state.os->nativeLibraryPath.c_str(),
(state.os->appFilesPath + "turnip/").c_str(), (state.os->publicAppFilesPath + "gpu/turnip/").c_str(),
"libvulkan_freedreno.so", "libvulkan_freedreno.so",
nullptr)}; nullptr)};
if (!libvulkanHandle) { if (!libvulkanHandle) {
@ -228,7 +228,7 @@ namespace skyline::gpu {
state.os->nativeLibraryPath.c_str(), state.os->nativeLibraryPath.c_str(),
nullptr, nullptr,
nullptr, nullptr,
(state.os->appFilesPath + "vk_file_redirect/").c_str()); (state.os->publicAppFilesPath + "gpu/vk_file_redirect/").c_str());
if (!libvulkanHandle) if (!libvulkanHandle)
libvulkanHandle = dlopen("libvulkan.so", RTLD_NOW); libvulkanHandle = dlopen("libvulkan.so", RTLD_NOW);
} }

View File

@ -16,13 +16,15 @@ namespace skyline::kernel {
OS::OS( OS::OS(
std::shared_ptr<JvmManager> &jvmManager, std::shared_ptr<JvmManager> &jvmManager,
std::shared_ptr<Settings> &settings, std::shared_ptr<Settings> &settings,
std::string appFilesPath, std::string publicAppFilesPath,
std::string privateAppFilesPath,
std::string nativeLibraryPath, std::string nativeLibraryPath,
std::string deviceTimeZone, std::string deviceTimeZone,
language::SystemLanguage systemLanguage, language::SystemLanguage systemLanguage,
std::shared_ptr<vfs::FileSystem> assetFileSystem) std::shared_ptr<vfs::FileSystem> assetFileSystem)
: nativeLibraryPath(std::move(nativeLibraryPath)), : nativeLibraryPath(std::move(nativeLibraryPath)),
appFilesPath(std::move(appFilesPath)), publicAppFilesPath(std::move(publicAppFilesPath)),
privateAppFilesPath(std::move(privateAppFilesPath)),
state(this, jvmManager, settings), state(this, jvmManager, settings),
deviceTimeZone(std::move(deviceTimeZone)), deviceTimeZone(std::move(deviceTimeZone)),
assetFileSystem(std::move(assetFileSystem)), assetFileSystem(std::move(assetFileSystem)),
@ -31,7 +33,7 @@ namespace skyline::kernel {
void OS::Execute(int romFd, loader::RomFormat romType) { void OS::Execute(int romFd, loader::RomFormat romType) {
auto romFile{std::make_shared<vfs::OsBacking>(romFd)}; auto romFile{std::make_shared<vfs::OsBacking>(romFd)};
auto keyStore{std::make_shared<crypto::KeyStore>(appFilesPath)}; auto keyStore{std::make_shared<crypto::KeyStore>(privateAppFilesPath + "keys/")};
state.loader = [&]() -> std::shared_ptr<loader::Loader> { state.loader = [&]() -> std::shared_ptr<loader::Loader> {
switch (romType) { switch (romType) {

View File

@ -15,7 +15,8 @@ namespace skyline::kernel {
class OS { class OS {
public: public:
std::string nativeLibraryPath; //!< The full path to the app's native library directory std::string nativeLibraryPath; //!< The full path to the app's native library directory
std::string appFilesPath; //!< The full path to the app's files directory std::string publicAppFilesPath; //!< The full path to the app's public files directory
std::string privateAppFilesPath; //!< The full path to the app's private files directory
DeviceState state; DeviceState state;
std::string deviceTimeZone; //!< The timezone name (e.g. Europe/London) std::string deviceTimeZone; //!< The timezone name (e.g. Europe/London)
std::shared_ptr<vfs::FileSystem> assetFileSystem; //!< A filesystem to be used for accessing emulator assets (like tzdata) std::shared_ptr<vfs::FileSystem> assetFileSystem; //!< A filesystem to be used for accessing emulator assets (like tzdata)
@ -29,7 +30,8 @@ namespace skyline::kernel {
OS( OS(
std::shared_ptr<JvmManager> &jvmManager, std::shared_ptr<JvmManager> &jvmManager,
std::shared_ptr<Settings> &settings, std::shared_ptr<Settings> &settings,
std::string appFilesPath, std::string publicAppFilesPath,
std::string privateAppFilesPath,
std::string deviceTimeZone, std::string deviceTimeZone,
std::string nativeLibraryPath, std::string nativeLibraryPath,
language::SystemLanguage systemLanguage, language::SystemLanguage systemLanguage,

View File

@ -17,7 +17,7 @@ namespace skyline::service::fssrv {
} }
Result IFileSystemProxy::OpenSdCardFileSystem(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) { Result IFileSystemProxy::OpenSdCardFileSystem(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
manager.RegisterService(std::make_shared<IFileSystem>(std::make_shared<vfs::OsFileSystem>(state.os->appFilesPath + "/switch/sdmc/"), state, manager), session, response); manager.RegisterService(std::make_shared<IFileSystem>(std::make_shared<vfs::OsFileSystem>(state.os->publicAppFilesPath + "/switch/sdmc/"), state, manager), session, response);
return {}; return {};
} }
@ -57,7 +57,7 @@ namespace skyline::service::fssrv {
} }
}()}; }()};
manager.RegisterService(std::make_shared<IFileSystem>(std::make_shared<vfs::OsFileSystem>(state.os->appFilesPath + "/switch" + saveDataPath), state, manager), session, response); manager.RegisterService(std::make_shared<IFileSystem>(std::make_shared<vfs::OsFileSystem>(state.os->publicAppFilesPath + "/switch" + saveDataPath), state, manager), session, response);
return {}; return {};
} }

View File

@ -37,7 +37,7 @@ namespace skyline::service::pl {
constexpr u32 SharedFontMagic{0x36F81A1E}; //!< The encrypted magic for a single font in the shared font data constexpr u32 SharedFontMagic{0x36F81A1E}; //!< The encrypted magic for a single font in the shared font data
constexpr u32 SharedFontKey{SharedFontMagic ^ SharedFontResult}; //!< The XOR key for encrypting the font size constexpr u32 SharedFontKey{SharedFontMagic ^ SharedFontResult}; //!< The XOR key for encrypting the font size
auto fontsDirectory{std::make_shared<vfs::OsFileSystem>(state.os->appFilesPath + "fonts/")}; auto fontsDirectory{std::make_shared<vfs::OsFileSystem>(state.os->publicAppFilesPath + "fonts/")};
auto ptr{reinterpret_cast<u32 *>(sharedFontMemory->host.ptr)}; auto ptr{reinterpret_cast<u32 *>(sharedFontMemory->host.ptr)};
for (auto &font : fonts) { for (auto &font : fonts) {
*ptr++ = 0x18029a7f; *ptr++ = 0x18029a7f;

View File

@ -75,11 +75,12 @@ class EmulationActivity : AppCompatActivity(), SurfaceHolder.Callback, View.OnTo
* @param romType The type of the ROM as an enum value * @param romType The type of the ROM as an enum value
* @param romFd The file descriptor of the ROM object * @param romFd The file descriptor of the ROM object
* @param preferenceFd The file descriptor of the Preference XML * @param preferenceFd The file descriptor of the Preference XML
* @param appFilesPath The full path to the app files directory * @param publicAppFilesPath The full path to the public app files directory
* @param privateAppFilesPath The full path to the private app files directory
* @param nativeLibraryPath The full path to the app native library directory * @param nativeLibraryPath The full path to the app native library directory
* @param assetManager The asset manager used for accessing app assets * @param assetManager The asset manager used for accessing app assets
*/ */
private external fun executeApplication(romUri : String, romType : Int, romFd : Int, preferenceFd : Int, language : Int, appFilesPath : String, nativeLibraryPath : String, assetManager : AssetManager) private external fun executeApplication(romUri : String, romType : Int, romFd : Int, preferenceFd : Int, language : Int, publicAppFilesPath : String, privateAppFilesPath : String, nativeLibraryPath : String, assetManager : AssetManager)
/** /**
* @param join If the function should only return after all the threads join or immediately * @param join If the function should only return after all the threads join or immediately
@ -218,7 +219,7 @@ class EmulationActivity : AppCompatActivity(), SurfaceHolder.Callback, View.OnTo
val preferenceFd = ParcelFileDescriptor.open(File("${applicationInfo.dataDir}/shared_prefs/${applicationInfo.packageName}_preferences.xml"), ParcelFileDescriptor.MODE_READ_WRITE) val preferenceFd = ParcelFileDescriptor.open(File("${applicationInfo.dataDir}/shared_prefs/${applicationInfo.packageName}_preferences.xml"), ParcelFileDescriptor.MODE_READ_WRITE)
emulationThread = Thread { emulationThread = Thread {
executeApplication(rom.toString(), romType, romFd.detachFd(), preferenceFd.detachFd(), settings.systemLanguage, applicationContext.filesDir.canonicalPath + "/", applicationInfo.nativeLibraryDir + "/", assets) executeApplication(rom.toString(), romType, romFd.detachFd(), preferenceFd.detachFd(), settings.systemLanguage, applicationContext.getPublicFilesDir().canonicalPath + "/", applicationContext.filesDir.canonicalPath + "/", applicationInfo.nativeLibraryDir + "/", assets)
returnFromEmulation() returnFromEmulation()
} }

View File

@ -45,7 +45,10 @@ object KeyReader {
if (!DocumentFile.isDocumentUri(context, uri)) if (!DocumentFile.isDocumentUri(context, uri))
return false return false
val tmpOutputFile = File("${context.filesDir.canonicalFile}/${keyType.fileName}.tmp") val outputDirectory = File("${context.filesDir.canonicalFile}/keys/")
if (!outputDirectory.exists())
outputDirectory.mkdirs()
val tmpOutputFile = File(outputDirectory, "${keyType.fileName}.tmp")
context.contentResolver.openInputStream(uri).use { inputStream -> context.contentResolver.openInputStream(uri).use { inputStream ->
tmpOutputFile.bufferedWriter().use { writer -> tmpOutputFile.bufferedWriter().use { writer ->

View File

@ -21,7 +21,6 @@ import androidx.core.content.res.use
import androidx.core.graphics.drawable.toBitmap import androidx.core.graphics.drawable.toBitmap
import androidx.core.view.isInvisible import androidx.core.view.isInvisible
import androidx.core.view.isVisible import androidx.core.view.isVisible
import androidx.core.view.size
import androidx.preference.PreferenceManager import androidx.preference.PreferenceManager
import androidx.recyclerview.widget.GridLayoutManager import androidx.recyclerview.widget.GridLayoutManager
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
@ -130,13 +129,12 @@ class MainActivity : AppCompatActivity() {
binding.searchBar.apply { binding.searchBar.apply {
binding.logIcon.setOnClickListener { binding.logIcon.setOnClickListener {
val file = applicationContext.filesDir.resolve("emulation.sklog") val file = applicationContext.getPublicFilesDir().resolve("logs/emulation.sklog")
if (file.length() != 0L) { if (file.exists() && file.length() != 0L) {
val uri = FileProvider.getUriForFile(this@MainActivity, "skyline.emu.fileprovider", file) val uri = FileProvider.getUriForFile(this@MainActivity, "skyline.emu.fileprovider", file)
val intent = Intent(Intent.ACTION_SEND) val intent = Intent(Intent.ACTION_SEND)
.setType("text/plain") .setDataAndType(uri, "text/plain")
.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION) .addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
.setData(uri)
.putExtra(Intent.EXTRA_STREAM, uri) .putExtra(Intent.EXTRA_STREAM, uri)
startActivity(Intent.createChooser(intent, getString(R.string.log_share_prompt))) startActivity(Intent.createChooser(intent, getString(R.string.log_share_prompt)))
} else { } else {

View File

@ -6,8 +6,15 @@
package emu.skyline package emu.skyline
import android.app.Application import android.app.Application
import android.content.Context
import dagger.hilt.android.HiltAndroidApp import dagger.hilt.android.HiltAndroidApp
import emu.skyline.di.getSettings import emu.skyline.di.getSettings
import java.io.File
/**
* @return The optimal directory for putting public files inside, this may return a private directory if a public directory cannot be retrieved
*/
fun Context.getPublicFilesDir() : File = getExternalFilesDir(null) ?: filesDir
@HiltAndroidApp @HiltAndroidApp
class SkylineApplication : Application() { class SkylineApplication : Application() {
@ -16,6 +23,9 @@ class SkylineApplication : Application() {
override fun onCreate() { override fun onCreate() {
super.onCreate() super.onCreate()
System.loadLibrary("skyline") System.loadLibrary("skyline")
initializeLog(applicationContext.filesDir.canonicalPath + "/", getSettings().logLevel.toInt())
val appFilesPath = applicationContext.getPublicFilesDir().canonicalPath
File("$appFilesPath/logs/").mkdirs()
initializeLog("$appFilesPath/", getSettings().logLevel.toInt())
} }
} }

View File

@ -128,7 +128,7 @@ internal class RomFile(context : Context, format : RomFormat, uri : Uri, systemL
init { init {
context.contentResolver.openFileDescriptor(uri, "r")!!.use { context.contentResolver.openFileDescriptor(uri, "r")!!.use {
result = LoaderResult.get(populate(format.ordinal, it.fd, context.filesDir.canonicalPath + "/", systemLanguage)) result = LoaderResult.get(populate(format.ordinal, it.fd, "${context.filesDir.canonicalPath}/keys/", systemLanguage))
} }
appEntry = applicationName?.let { name -> appEntry = applicationName?.let { name ->

View File

@ -1,4 +1,5 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<paths> <paths>
<files-path path="/" name="Skyline" /> <files-path path="/" name="Skyline Internal" />
<external-files-path path="/" name="Skyline External" />
</paths> </paths>