Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WIP: Fix Android bug on FAT32 time resolution and mtime caching #360

Draft
wants to merge 3 commits into
base: master
Choose a base branch
from

Conversation

lmagyar
Copy link
Contributor

@lmagyar lmagyar commented Jun 10, 2024

As I wrote in #351 (comment), Android lies about the lastModifiedTime. Even the specs says, that if the time resolution is lower than what we ask, the next getLastModifiedTime will give back the "truncated" value, this is simply not true (tested on real phone, Android 9.0 and emulator). It gives back the truncated values only when he wants, usually hours later. This is an unpredictable nightmare.

This fix:

  • adds a new method to the StorageManagerUtil class that detects SAF filesystems from /proc/mounts, it detects:
    • FAT16, FAT32 -> 2000ms
    • exFAT -> 10ms
    • default 1ms
  • moves the fileSystemView property from SafSshFile up to SafFile, so all SAF file can call the new getTimeResolution() from SafFileSystemView

Maybe the default 1ms is overkill, in theory FTP has sub-second resolution, though we can modify StorageManagerUtil to return only 1000 vs 2000 ms, in this case no overload needed in SafSshFileSystemView to limit sub second resolution to the 1s resolution of sftp messages.

@lmagyar
Copy link
Contributor Author

lmagyar commented Jun 10, 2024

Not the latest logs, but some proof it works.
Emulator:

getFilesystemTimeResolutionForSftp(content://com.android.externalstorage.documents/tree/17FB-0715...
  found mount point /mnt/media_rw/17FB-0715 with type vfat

Real FAT32 card:

getFilesystemTimeResolutionForSftp(content://com.android.externalstorage.documents/tree/80AB-022A...
  found mount point /mnt/media_rw/80AB-022A with type sdfat with option fs=vfat:32

The fs=exfat sample in the code comment is from a real exFAT 64GB card.

@@ -47,6 +54,44 @@ public static String getFullDocIdPathFromTreeUri(@Nullable final Uri treeUri, Co
}
}

public static int getFilesystemTimeResolutionForTreeUri(Uri startUrl) {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

add javadoc comment here, that returned time resolution is in milliseconds

// /dev/block/vold/public:xxx,xx /mnt/media_rw/XXXX-XXXX sdfat ...,fs=vfat:16,... 0 0 -> 2000 ms
// /dev/block/vold/public:xxx,xx /mnt/media_rw/XXXX-XXXX sdfat ...,fs=vfat:32,... 0 0 -> 2000 ms
// /dev/block/vold/public:xxx,xx /mnt/media_rw/XXXX-XXXX sdfat ...,fs=exfat,... 0 0 -> 10 ms
for (String line; (line = br.readLine()) != null; ) {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

log "line" as trace, please, that will help if some users report issues with this somewhen in future

return new SafSshFile(contentResolver, parentDocumentFile, documentFile, absPath, pftpdService, session, this);
PftpdService pftpdService,
SafFileSystemView fileSystemView) {
return new SafSshFile(contentResolver, parentDocumentFile, documentFile, absPath, pftpdService, fileSystemView, session);
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should not take SafFileSystemView as parameter, but pass "this" instead

@@ -76,7 +74,7 @@ public SshFile getParentFile() {
parentPath = "/";
}
logger.trace("[{}] getParentFile() -> {}", name, parentPath);
return fileSystemView.getFile(parentPath);
return (SshFile)fileSystemView.getFile(parentPath);
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why is this cast necessary? why was it not before?

logger.trace("createFile(DocumentFile)");
return new SafFtpFile(contentResolver, parentDocumentFile, documentFile, absPath, pftpdService, user);
return new SafFtpFile(contentResolver, parentDocumentFile, documentFile, absPath, pftpdService, fileSystemView, user);
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should not take SafFileSystemView as parameter, but pass "this" instead

logger.trace("createFile(String)");
return new SafFtpFile(contentResolver, parentDocumentFile, name, absPath, pftpdService, user);
return new SafFtpFile(contentResolver, parentDocumentFile, name, absPath, pftpdService, fileSystemView, user);
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should not take SafFileSystemView as parameter, but pass "this" instead

@wolpi
Copy link
Owner

wolpi commented Jun 23, 2024

I'm really looking forward to that merge script 😄

@lmagyar
Copy link
Contributor Author

lmagyar commented Jun 23, 2024

I'm really looking forward to that merge script 😄

The Python sync? 😄 It is working, I've added remote management (start/stop, with Automate or HomeAssistant) for Tailscale, pFTPd, Termux/sshd services (the later for inotifywait, to catch the changes on the fly). I need a few hours net to finalize it on to a v0.1 quality level, though with a newborn and a relocation I hardly find time to sleep. 😨

I will work on the tech comments above on next week.

@wolpi
Copy link
Owner

wolpi commented Jun 26, 2024

Happy coding between moving boxes and with new born on arm 😄

@lmagyar lmagyar marked this pull request as draft August 30, 2024 18:28
@lmagyar lmagyar changed the title Fix Android bug on FAT32 time resolution and mtime caching WIP: Fix Android bug on FAT32 time resolution and mtime caching Sep 3, 2024
@lmagyar
Copy link
Contributor Author

lmagyar commented Sep 3, 2024

Happy coding between moving boxes and with new born on arm 😄

Yeah, this description is quite accurate. :)

Just a note:

Android inaccurate on file mod. times not only on files we have uploaded, but on eg. new pictures. When we download a fresh new picture through plain-old FS from the SD card, it will have an inaccurate timestamp, but a few hours later it will be rounded to 2s (in case of FAT32) and my sync script will download it again. Not a big issue, doesn't happen too often, but an issue, especially when I delete the downloaded file, and the delete and "modification" causes a conflict.

So this solution should be extended to RoSaf and plain-old FS (when we access files under /fs/storage/XXXX-XXXX). Not a big problem, but it needs some time.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants