Ensure FUSE session start is synchronous
When mounting a volume, the following calls should happen
synchronously: vold 1-> system_server 2-> fuse_daemon.
Previously, in (2), we would spin a separate thread to start the FUSE
session because the libfuse call to start a session blocks forever
when successful. This means that we may return back to vold even if
the session wasn't properly started.
When we return to vold, it would proceed to mount Android/ and
Android/obb bind mounts on the FUSE mount. If the FUSE session is not
ready, FUSE_LOOKUPS from vold would block until ready.
In practice, the blocking is usually not a problem because the FUSE
daemon would be up any moment and vold would unblock. However, we have
hit watchdog triggered runtime restarts recently where vold was wedged
for >30s on IO to the FUSE mount.
It is unclear what went wrong in those cases and we've added the FUSE
daemon to the 'interesting' Java processes for the watchdog to dump
when the system ANRs, I3d6e52f8dad08c2ee5d520274f9a9f522f5ab9d3. This
will give us more insight into what happened.
In any case, this cl removes the risk of vold wedging because the FUSE
session could not start (quickly).
The main principle here is that the FUSE daemon will poll for some
time (5s) for the session to start, if it doesn't, the process aborts,
closing the /dev/fuse fd and unwedging any processes waiting on FUSE
IO (as long as other /dev/fuse fd dups are closed which they should
be).
Bug: 150525627
Bug: 149970494
Test: Adding an artificial sleep in before pf_init doesn't wedge vold
anymore
Merged-In: Icf478443a686feace8716f307e96d975dffb4421
Change-Id: Icf478443a686feace8716f307e96d975dffb4421
diff --git a/jni/com_android_providers_media_FuseDaemon.cpp b/jni/com_android_providers_media_FuseDaemon.cpp
index bede40a..9a79412 100644
--- a/jni/com_android_providers_media_FuseDaemon.cpp
+++ b/jni/com_android_providers_media_FuseDaemon.cpp
@@ -50,6 +50,13 @@
daemon->Start(fd, utf_chars_path.c_str());
}
+bool com_android_providers_media_FuseDaemon_is_started(JNIEnv* env, jobject self,
+ jlong java_daemon) {
+ LOG(DEBUG) << "Checking if FUSE daemon started...";
+ const fuse::FuseDaemon* daemon = reinterpret_cast<fuse::FuseDaemon*>(java_daemon);
+ return daemon->IsStarted();
+}
+
void com_android_providers_media_FuseDaemon_delete(JNIEnv* env, jobject self, jlong java_daemon) {
LOG(DEBUG) << "Destroying the FUSE daemon...";
fuse::FuseDaemon* const daemon = reinterpret_cast<fuse::FuseDaemon*>(java_daemon);
@@ -106,6 +113,8 @@
reinterpret_cast<void*>(com_android_providers_media_FuseDaemon_should_open_with_fuse)},
{"native_is_fuse_thread", "()Z",
reinterpret_cast<void*>(com_android_providers_media_FuseDaemon_is_fuse_thread)},
+ {"native_is_started", "(J)Z",
+ reinterpret_cast<void*>(com_android_providers_media_FuseDaemon_is_started)},
{"native_invalidate_fuse_dentry_cache", "(JLjava/lang/String;)V",
reinterpret_cast<void*>(
com_android_providers_media_FuseDaemon_invalidate_fuse_dentry_cache)}};