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
This commit is contained in:
parent
2309f76d17
commit
89f74fbf25
5 changed files with 47 additions and 18 deletions
|
@ -113,6 +113,7 @@ status_t EmulatedVolume::doUnmount() {
|
|||
mFusePid = 0;
|
||||
}
|
||||
|
||||
KillProcessesUsingPath(getPath());
|
||||
ForceUnmount(mFuseDefault);
|
||||
ForceUnmount(mFuseRead);
|
||||
ForceUnmount(mFuseWrite);
|
||||
|
|
|
@ -177,13 +177,14 @@ extern "C" void vold_killProcessesWithOpenFiles(const char *path, int signal) {
|
|||
/*
|
||||
* Hunt down processes that have files open at the given mount point.
|
||||
*/
|
||||
void Process::killProcessesWithOpenFiles(const char *path, int signal) {
|
||||
DIR* dir;
|
||||
int Process::killProcessesWithOpenFiles(const char *path, int signal) {
|
||||
int count = 0;
|
||||
DIR* dir;
|
||||
struct dirent* de;
|
||||
|
||||
if (!(dir = opendir("/proc"))) {
|
||||
SLOGE("opendir failed (%s)", strerror(errno));
|
||||
return;
|
||||
return count;
|
||||
}
|
||||
|
||||
while ((de = readdir(dir))) {
|
||||
|
@ -213,7 +214,9 @@ void Process::killProcessesWithOpenFiles(const char *path, int signal) {
|
|||
if (signal != 0) {
|
||||
SLOGW("Sending %s to process %d", strsignal(signal), pid);
|
||||
kill(pid, signal);
|
||||
count++;
|
||||
}
|
||||
}
|
||||
closedir(dir);
|
||||
return count;
|
||||
}
|
||||
|
|
|
@ -21,7 +21,7 @@
|
|||
|
||||
class Process {
|
||||
public:
|
||||
static void killProcessesWithOpenFiles(const char *path, int signal);
|
||||
static int killProcessesWithOpenFiles(const char *path, int signal);
|
||||
static int getPid(const char *s);
|
||||
static int checkSymLink(int pid, const char *path, const char *name);
|
||||
static int checkFileMaps(int pid, const char *path);
|
||||
|
|
50
Utils.cpp
50
Utils.cpp
|
@ -123,35 +123,57 @@ status_t ForceUnmount(const std::string& path) {
|
|||
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;
|
||||
|
|
3
Utils.h
3
Utils.h
|
@ -49,6 +49,9 @@ status_t PrepareDir(const std::string& path, mode_t mode, uid_t uid, gid_t gid);
|
|||
/* Really unmounts the path, killing active processes along the way */
|
||||
status_t ForceUnmount(const std::string& path);
|
||||
|
||||
/* Kills any processes using given path */
|
||||
status_t KillProcessesUsingPath(const std::string& path);
|
||||
|
||||
/* Creates bind mount from source to target */
|
||||
status_t BindMount(const std::string& source, const std::string& target);
|
||||
|
||||
|
|
Loading…
Reference in a new issue