Kill apps using storage through bind mounts.
When unmounting an emulated volume, look for apps with open files
using the final published volume path.
Without this change, we were only looking at the internal paths
used for runtime permissions, which apps never use directly. This
meant we'd always fail to unmount the volume if apps didn't respect
the EJECTING broadcast, and volume migration would end up wedged
until the device rebooted.
Bug: 24863778
Change-Id: Ibda484e66ab95744c304c344b226caa5b10b7e2e
diff --git a/Utils.cpp b/Utils.cpp
index e19c9df..f352e84 100644
--- a/Utils.cpp
+++ b/Utils.cpp
@@ -123,35 +123,57 @@
if (!umount2(cpath, UMOUNT_NOFOLLOW) || errno == EINVAL || errno == ENOENT) {
return OK;
}
- PLOG(WARNING) << "Failed to unmount " << path;
-
+ // Apps might still be handling eject request, so wait before
+ // we start sending signals
sleep(5);
+
Process::killProcessesWithOpenFiles(cpath, SIGINT);
-
+ sleep(5);
if (!umount2(cpath, UMOUNT_NOFOLLOW) || errno == EINVAL || errno == ENOENT) {
return OK;
}
- PLOG(WARNING) << "Failed to unmount " << path;
- sleep(5);
Process::killProcessesWithOpenFiles(cpath, SIGTERM);
-
- if (!umount2(cpath, UMOUNT_NOFOLLOW) || errno == EINVAL || errno == ENOENT) {
- return OK;
- }
- PLOG(WARNING) << "Failed to unmount " << path;
-
sleep(5);
- Process::killProcessesWithOpenFiles(cpath, SIGKILL);
-
if (!umount2(cpath, UMOUNT_NOFOLLOW) || errno == EINVAL || errno == ENOENT) {
return OK;
}
- PLOG(ERROR) << "Failed to unmount " << path;
+
+ Process::killProcessesWithOpenFiles(cpath, SIGKILL);
+ sleep(5);
+ if (!umount2(cpath, UMOUNT_NOFOLLOW) || errno == EINVAL || errno == ENOENT) {
+ return OK;
+ }
return -errno;
}
+status_t KillProcessesUsingPath(const std::string& path) {
+ const char* cpath = path.c_str();
+ if (Process::killProcessesWithOpenFiles(cpath, SIGINT) == 0) {
+ return OK;
+ }
+ sleep(5);
+
+ if (Process::killProcessesWithOpenFiles(cpath, SIGTERM) == 0) {
+ return OK;
+ }
+ sleep(5);
+
+ if (Process::killProcessesWithOpenFiles(cpath, SIGKILL) == 0) {
+ return OK;
+ }
+ sleep(5);
+
+ // Send SIGKILL a second time to determine if we've
+ // actually killed everyone with open files
+ if (Process::killProcessesWithOpenFiles(cpath, SIGKILL) == 0) {
+ return OK;
+ }
+ PLOG(ERROR) << "Failed to kill processes using " << path;
+ return -EBUSY;
+}
+
status_t BindMount(const std::string& source, const std::string& target) {
if (::mount(source.c_str(), target.c_str(), "", MS_BIND, NULL)) {
PLOG(ERROR) << "Failed to bind mount " << source << " to " << target;