Sometimes randomly Volley crashes my app upon startup, it crashes in the application class and a user would not be able to open the app again until they go into settings and
I experienced the same issue.
We knew we didn't have files that were GBs in size on initialization of the cache. It also occurred when reading header strings, which should never be GBs in length.
So it looked like the length was being read incorrectly by readLong.
We had two apps with roughly identical setups, except that one app had two independent processes created on start up. The main application process and a 'SyncAdapter' process following the sync adapter pattern. Only the app with two processes would crash. These two processes would independently initialize the cache.
However, the DiskBasedCache uses the same physical location for both processes. We eventually concluded that concurrent initializations were resulting in concurrent reads and writes of the same files, leading to bad reads of the size parameter.
I don't have a full proof that this is the issue, but I'm planning to work on a test app to verify.
In the short term, we've just caught the overly large byte allocation in streamToBytes, and throw an IOException so that Volley catches the exception and just deletes the file. However, it would probably be better to use a separate disk cache for each process.
private static byte[] streamToBytes(InputStream in, int length) throws IOException {
byte[] bytes;
// this try-catch is a change added by us to handle a possible multi-process issue when reading cache files
try {
bytes = new byte[length];
} catch (OutOfMemoryError e) {
throw new IOException("Couldn't allocate " + length + " bytes to stream. May have parsed the stream length incorrectly");
}
int count;
int pos = 0;
while (pos < length && ((count = in.read(bytes, pos, length - pos)) != -1)) {
pos += count;
}
if (pos != length) {
throw new IOException("Expected " + length + " bytes, read " + pos + " bytes");
}
return bytes;
}