2

First, I did read this post about this exception carefully, but the answers cannot explain my case. I don't think permission is an issue here.

The code:

Serializer serializer = new Persister();
File fFoo= new File(context.getFilesDir(), "foo.xml");
serializer.write(fooObject, fFoo);

serializer.write() throws the following exception once in a while:

 Stack trace: java.io.FileNotFoundException: /data/data/net.foo.appfoo/files/foo.xml: open failed: EROFS (Read-only file system)
    at libcore.io.IoBridge.open(IoBridge.java:460)
    at java.io.FileOutputStream.<init>(FileOutputStream.java:88)
    at java.io.FileOutputStream.<init>(FileOutputStream.java:73)
    at org.simpleframework.xml.core.Persister.write(SourceFile:1198)

Could anyone point to a possible scenario for this to happen?

Hong
  • 17,643
  • 21
  • 81
  • 142
  • 1
    This is happening in production code? The only production scenario I know of where this would happen is if you changed `android:sharedUserId` values. – CommonsWare Jul 16 '19 at 23:26
  • Yes, it reported by analytics. I cannot reproduce it on my testing devices. It is my first time to hear android:sharedUserId. How can this happen? – Hong Jul 16 '19 at 23:29
  • 1
    `android:sharedUserId` is an attribute you can put on ``. If 2+ apps have the same `sharedUserId` and are signed by the same signing key, they can read/write each others files on internal storage. However, if you *change* the `sharedUserId` value for a shipping app -- including adding one after having shipped originally without it -- existing users will be locked out of their internal storage files. Android switches the Linux uid that the app runs as, but it does not change the ownership of the files. – CommonsWare Jul 16 '19 at 23:32
  • 1
    I am guessing that you did not change `android:sharedUserId`. If you only get this crash report from one user and device, perhaps somebody is playing with reverse-engineering your app and somehow botched the file ownership. Or, perhaps this is a user with a rooted device, and they accidentally changed file permissions. – CommonsWare Jul 16 '19 at 23:34
  • Thanks a lot for the elucidation. Could you combine your comments into an answer for me to accept? – Hong Jul 16 '19 at 23:42

1 Answers1

1

One scenario that can explain this is a change in android:sharedUserId.

android:sharedUserId is an attribute you can put on <manifest>. If 2+ apps have the same sharedUserId and are signed by the same signing key, they can read/write each others files on internal storage.

However, if you change the sharedUserId value for a shipping app — including adding one after having shipped originally without it — existing users will be locked out of their internal storage files. Android switches the Linux uid that the app runs as, but it does not change the ownership of the files. As a result, the app no longer has rights to its files. This is the exception that I would expect to see in this case.

It is this sort of problem that caused Google to finally deprecate android:sharedUserId in Android Q, with a plan to formally discontinue it in a future release.

In your case, I am guessing that you did not set or change android:sharedUserId.


That is the only scenario that I know of where internal storage for your app would be reported as read-only, where you as the developer caused the problem.

Everything else that I can think of is outside of your control:

  • Perhaps the user rooted their device and accidentally changed file ownership or file permissions on your files

  • Perhaps the user is a script kiddie who is reverse-engineering your app and is fussing around with android:sharedUserId

  • Perhaps the user has been hit with ransomware, and part of its attack was to change permissions on app files via some security flaw

CommonsWare
  • 986,068
  • 189
  • 2,389
  • 2,491