Commit Graph
349 Commits
Author SHA1 Message Date
Henrik Rydgård 0e3dfcef9d Merge pull request #22454 from hrydgard/android-activity-lifecycle
More Android activity lifecycle fixes
2026-10-08 20:10:14 +02:00
Henrik RydgårdandClaude Opus 5.5 08c1a6907a Don't chmod existing parent directories in CreateFullPath
CreateDir's "repair" of existing directories ran for every component
CreateFullPath walked through, so creating any directory under the
user's home made the home directory itself group-writable (775). That
breaks zsh's compinit ("insecure directories") among other things.

Only repair the permissions of the target directory itself, when it
already exists.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-08 19:13:18 +02:00
Henrik RydgårdandClaude Fable 5.1 2f6bb8d55e Android: Don't leak the activity on recreate, and hand it over safely
registerCallbacks took a new global ref to the activity on every onCreate
without releasing the previous one, and unregisterCallbacks only runs on a
real shutdown. Since rotation and resizing recreate the activity, each of
those leaked the old one, view hierarchy and all.

Releasing it means other threads can no longer use the raw global ref,
which had been copied into AndroidStorage and TextDrawerAndroid and was
read from the emu thread and IO threads. They now take a local ref under a
mutex (Android_GetActivity, and the equivalent inside AndroidStorage for
the shortcut activity's sake), so a call in flight keeps its activity
alive while the UI thread swaps in the new one.

The "no activity" bail is a null check on that local ref rather than a
separate HasActivity() test beforehand. Between such a test and the call
the UI thread can swap the activity out, and we'd hand null to a Java
method that wants a Context. The one remaining HasActivity() caller never
passes the activity on, so it has nothing to race with.

The ContentUri class ref and method IDs are now only looked up once,
instead of leaking a class ref per activity.

Headless and the unit test executable link Common but not app-android.cpp, so
they get a stub for this the same way they already do for getEnv and findClass.
Without it the Android CI build fails at link time, where a normal gradle build
is perfectly happy.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01152igCdjTNhT29qvphPyPC
2026-10-08 18:54:46 +02:00
Henrik RydgårdandClaude Fable 5.1 35c586b27b Android: Stop leaking JNI local references on native threads
Local refs are only freed automatically when a native method returns to
Java. The content URI functions mostly run on threads we attached
ourselves, where nothing ever freed the strings they created - two per
file open, one per exists check and so on. From Android 8 that's a slow
leak; before it the table has 512 slots and overflowing it aborts.

Add JNILocalFrame (PushLocalFrame/PopLocalFrame) and use it in all of
AndroidStorage.cpp, in the camera device list, and free the name string
in findClass.

Also: Android_GetFileInfo never released its GetStringUTFChars buffer, a
native leak on every call, and Android_ListContentUri called
GetArrayLength on a null array if the Java side returned none.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-08 18:54:46 +02:00
Henrik Rydgård 80b7fe77ba Create directories with 775 permissions instead of 755.
Helps some Android save sync tools.
2026-10-01 09:57:21 -06:00
Henrik RydgårdandClaude Opus 5 4ae682283c Path: make WithReplacedExtension(old, new) report a mismatch instead of hiding it
It used to return the path unchanged when the path didn't end in oldExtension,
so a caller that guessed wrong silently went on using the original file - and
"the screenshot next to this savestate" quietly becomes "this savestate".
Every caller had to know to check the extension first, and most didn't.

Now it's [[nodiscard]] bool with an out-param, in the style of ComputePathTo
next door, so the mismatch has to be handled. Changing the signature rather
than the behaviour means no call site can keep the old assumption by accident.
All four callers wanted "skip it" or "fall back", which they now say out loud.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-12 11:54:11 -06:00
Henrik Rydgård c71fa5e32b sceIo: stop clobbering st_private, report FAT permissions, implement sceIoChstat
Cashing in the io/stat and io/shortname recordings.

__IoGetStat began with memset(stat, 0xfe, sizeof(SceIoStat)), which destroyed 24 bytes of the
caller's buffer that a real PSP never touches - it writes only as far as the timestamps and
leaves all six st_private words exactly as it found them. It also wrote a made-up sector number
into st_private[0] on the memory stick. That word carries the LBN on a UMD, which games read to
build disc0:/sce_lbn paths, so it stays for non-FAT and is left alone otherwise.

FAT has no permissions of its own and everything reads back as 0777. We were passing the host's
idea of the file through instead. The existing "all files look executable on FAT" hack for Beats
(issue #14812) was right in substance but lived only in sceIoDread, so sceIoGetstat and
sceIoDread disagreed about the same file where hardware has them agree. Both now go through one
path, which also gets the read-only case right: no write bits means mode 0555 and attr 0x21.

sceIoGetstat on the root of a volume is refused, as on hardware.

sceIoChstat was a logging stub. It now applies the read-only flag, which is what st_mode's write
bits and st_attr's 0x01 both mean on FAT - setting either produces both, and it's reversible.
That needs a new IFileSystem::SetFileWritable, defaulting to "can't" so read-only filesystems and
hosts that can't express it (Android content URIs) are unaffected; the call still succeeds there,
since hardware would have.

GenerateFatShortNames now accounts for capitalisation. FAT keeps a lowercase flag for the base and
another for the extension, but the PSP only honours the base one, so "shrt" becomes SHRT while
"readme.txt" becomes README~1.TXT. We were only adding a counter on collision. The unit test
carries the whole recorded set, including the corrected README~1.MD.

io/shortname stays in tests_next: its d_name column can't match while SimulateVFATBug is
uppercasing lowercase 8.3 names, which is deliberate and load-bearing for homebrew.
2026-09-10 09:52:01 -06:00
Henrik RydgårdandClaude Opus 5 afeab27186 Don't load RAIntegration from an install we can't write to
RAIntegration keeps its cache and local achievement data next to the
executable. If PPSSPP is installed somewhere that needs elevation to write -
Program Files being the obvious case - that write fails and takes the emulator
down as soon as a set or code notes are loaded, with no log to show for it since
the log can't be written either.

Check whether the exe directory is writable before handing the DLL to rcheevos,
and if it isn't, say so and point at the portable .zip instead. Achievements
themselves still work, so carry on to the normal login.

Fixes #21260

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GgACRqkQNpfJQ4fjwyoEup
2026-09-05 16:15:45 -06:00
Henrik Rydgård 786a1530de Correct host0: mount 2026-08-24 09:30:44 +02:00
Henrik Rydgård 632fa10b23 Use VFS directly to read HLE-sceFont fonts instead of relying on the flash0: mount 2026-08-24 09:30:42 +02:00
Henrik Rydgård c6061aebca Debugger: don't persist log.channel.set changes to the saved config
log.channel.set is meant for temporary, session-only diagnostic
tweaks (e.g. quieting a noisy channel while investigating something
over the WebSocket debugger). It was going through the same
SetLogLevel/SetEnabled calls the UI settings use, so a normal app
exit would persist whatever channels/levels the debugger last left
set, silently overwriting the user's real saved log preferences for
future runs - discovered when a later session's default logging
looked "off" for no apparent reason.

LogManager now tracks whether the debugger has touched channel
config this run and skips SaveConfig() entirely if so, leaving
whatever's already on disk untouched.
2026-08-21 10:32:21 +02:00
Henrik RydgårdandClaude Sonnet 5 df751d5571 URL/VFS: fix latent pointer/index UB on empty or tiny input
UriDecode() formed SRC_END - 2 unconditionally, a pointer before the
start of the buffer (UB) for a 0- or 1-byte input. IsLocalAbsolutePath()
indexed path[0]/path[1] on a std::string_view with no bounds check,
UB for an empty path (path[0]) or a 1-byte path on Windows (path[1]).
Neither was known to crash in practice, but both are real UB flagged
by hardened/UBSan builds and easy to trigger (e.g. an empty query
string, or listing the VFS root).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01L4QAoxV2KY7ek4PcZw3WvY
2026-08-10 11:26:39 +02:00
Henrik RydgårdandClaude Sonnet 5 6ee6641fe5 ZipFileReader: guard against implausible/overflowing declared sizes
ReadFile()/ReadSingleFileFromZip() allocated/resized directly off a
zip entry's declared uncompressed size with no sanity check. A
crafted size near UINT64_MAX would wrap ReadFile()'s "size + 1" to 0,
allocating almost nothing while zip_fread() still writes the full
declared size into it - a length-field-driven heap overflow from a
malicious zip/texture pack. Both now reject entries above a generous
4GB cap. Also fixes GetFileInfo() reading zstat.name[strlen(name)-1]
unchecked, which underflows to SIZE_MAX for a zero-length entry name.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01L4QAoxV2KY7ek4PcZw3WvY
2026-08-10 11:26:24 +02:00
Henrik Rydgård 092ab42fe7 Clean up ugly usage of the g_nativeLibDir global. Now it's local in VulkanLoader. 2026-08-06 18:12:04 +02:00
Henrik Rydgård 551e4cd0ab Headless: Make all GPU backends work correctly on Windows 2026-08-05 00:15:56 +02:00
Henrik Rydgård e30b90e709 Quiet and improve some logs 2026-07-27 18:37:28 +02:00
Henrik Rydgård 4bf36fc7f8 Add command line option --vsh to try to boot the VSH. Logspam reduction, improve printf logs. 2026-07-27 14:58:59 +02:00
Henrik Rydgård 8cfd63b86d Apple buildfix 2026-07-24 22:47:29 +02:00
Henrik Rydgård 7600ec42dd PathBrowser: Rework synchronization. Remove unused enum value in LaunchUrlType. 2026-05-10 23:41:39 +02:00
Henrik Rydgård 0a0b4b9d95 Make opening 7z file android-compatible. Assorted buildfixes. 2026-03-27 14:34:18 -06:00
Henrik Rydgård 288b72cb16 Add 7z streaming support, so we can have a progress bar 2026-03-27 14:34:18 -06:00
Henrik Rydgård 5e0a9a0113 Add really simple 7z extraction, using the 7z VFS 2026-03-27 14:34:18 -06:00
Henrik Rydgård 0c077acc74 Do some include untangling, to limit the spread of the Windows.h include from SevenZipFileReader.h 2026-03-27 14:34:18 -06:00
Henrik Rydgård 8380e13f10 Add AI-generated SevenZipFileReader 2026-03-27 14:34:18 -06:00
Henrik Rydgård 116c31e7d9 Add the LZMA sdk 2026-03-27 14:34:15 -06:00
Henrik Rydgård d596e43b4b Android: Scale down selected background images when too large. Fix activity issue. 2026-03-08 14:53:20 +01:00
Henrik Rydgård a2de96a4d1 iOS: Try to avoid leaking file bookmarks. Don't try to install zips into iCloud folder. 2026-03-08 10:20:24 +01:00
Henrik Rydgård e8d648e91d InstallZip: Fix problem where the delete-after option didn't work
The file was held open.
2026-03-06 10:57:22 +01:00
Henrik Rydgård 8f138a76f6 Small refactor in DirListing.cpp 2026-02-23 14:22:30 +01:00
Henrik Rydgård 16a79e12b6 Scrollview: Disallow scrolling with mouse buttons other than the first.
Some logging cleanup
2026-02-23 11:48:11 +01:00
Henrik Rydgård aa750157c9 Add support for high-precision file timestamps on Windows 2026-02-23 11:17:47 +01:00
Henrik Rydgård dac2407a36 sceIo: Add support for microseconds in filetimes (not implemented in platforms yet) 2026-02-23 11:04:17 +01:00
Henrik Rydgård 5a5c7028b9 Assorted warning fixes and data initialization to please valgrind 2026-02-19 11:24:46 +01:00
Henrik Rydgård 2c0bdcf678 InstallZipScreen improvements, small cleanup 2026-02-10 11:34:59 +01:00
Henrik Rydgård 4ccd41110b Correctly do the VFS refactor that I tried to do in #21218
See #21218
2026-02-09 13:08:44 +01:00
Henrik Rydgård dd648b596c Revert "VFS: Remove some code duplication" (logic bug)
This reverts commit f257ad4f7f.
2026-02-08 18:44:48 +01:00
Henrik Rydgård f257ad4f7f VFS: Remove some code duplication 2026-02-08 00:53:50 +01:00
Henrik Rydgård dd28f75852 Buildfixes 2026-02-07 12:03:44 +01:00
Henrik Rydgård e0a09a8733 Prevent bad noise when dragging volume slider 2026-02-06 14:45:23 +01:00
Henrik Rydgård b1fa6b4671 Remove some uses of textScale 2026-02-06 14:30:47 +01:00
Henrik Rydgård de702ced45 Use std::string_view in VFS 2026-02-06 13:22:35 +01:00
Henrik Rydgård f8077347e4 FileSystems: Change multiple internal functions to take std::string_view 2026-02-06 12:31:49 +01:00
Henrik Rydgård 35da931fb3 Minor libretro vfs logging improvements
See #21140
2026-01-22 09:12:19 +01:00
Henrik Rydgård 3f3b353350 Merge pull request #21092 from white-axe/libretro-vfs
Use the libretro VFS interface in libretro builds
2026-01-10 16:36:01 +01:00
刘皓 a950879dd5 Don't use lseek64() in FileUtil.cpp 2026-01-09 11:46:12 -05:00
Henrik Rydgård 884d3c46d5 Rework listing of savestates - a single scan operation instead of lots of File::Exists and ModTime calls.
Needed to improve scalability on Android for when we increase the number
of states.
2026-01-09 11:17:21 +01:00
Henrik Rydgård e6e82c9ad3 Add java-side prefix filtering for ContentUri directory listing 2026-01-09 10:12:15 +01:00
刘皓 e72f288a7b Flush FILE buffers before using lseek64() 2026-01-09 00:54:51 -05:00
Henrik Rydgård e33ff46ffd Extract the rewind code from SaveState.cpp, to make it more managable. 2026-01-08 22:22:46 +01:00
刘皓 0b3cf1de8d Check that source is non-null before attempting to use it in the ZipContainer constructor 2026-01-08 11:59:12 -05:00