Move even more vold commands over to Binder.
This moves fstrim, obb and appfuse commands over to the new Binder interface. This change also separates creating/destroying and mounting/unmounting of OBB volumes, which means they finally flow nicely into the modern VolumeInfo/VolumeBase design. We now generate unique identifiers for all OBB volumes, instead of using a shady MD5 hash. Change all "loop" and "dm" devices to tag the kernel resources with a vold-specific prefix so that we can clean them up if vold crashes; there are new destroyAll() methods that handle this cleanup. Move appfuse mounting/unmounting into VolumeManager so it can be shared. Move various model objects into a separate directory to tidy things up. Test: cts-tradefed run commandAndExit cts-dev -m CtsOsTestCases -t android.os.storage.cts.StorageManagerTest Bug: 13758960 Change-Id: I7294e32b3fb6efe07cb3b77bd20166e70b66958f
This commit is contained in:
parent
a94fc7cdcd
commit
11c2d380a7
26 changed files with 674 additions and 232 deletions
11
Android.mk
11
Android.mk
|
@ -18,11 +18,12 @@ common_src_files := \
|
|||
Ext4Crypt.cpp \
|
||||
VoldUtil.c \
|
||||
cryptfs.cpp \
|
||||
Disk.cpp \
|
||||
VolumeBase.cpp \
|
||||
PublicVolume.cpp \
|
||||
PrivateVolume.cpp \
|
||||
EmulatedVolume.cpp \
|
||||
model/Disk.cpp \
|
||||
model/VolumeBase.cpp \
|
||||
model/PublicVolume.cpp \
|
||||
model/PrivateVolume.cpp \
|
||||
model/EmulatedVolume.cpp \
|
||||
model/ObbVolume.cpp \
|
||||
Utils.cpp \
|
||||
MoveTask.cpp \
|
||||
Benchmark.cpp \
|
||||
|
|
|
@ -44,7 +44,7 @@
|
|||
|
||||
#include "CommandListener.h"
|
||||
#include "VolumeManager.h"
|
||||
#include "VolumeBase.h"
|
||||
#include "model/VolumeBase.h"
|
||||
#include "ResponseCode.h"
|
||||
#include "Process.h"
|
||||
#include "Loop.h"
|
||||
|
@ -53,7 +53,6 @@
|
|||
#include "TrimTask.h"
|
||||
|
||||
#define DUMP_ARGS 0
|
||||
#define DEBUG_APPFUSE 0
|
||||
|
||||
using android::base::unique_fd;
|
||||
|
||||
|
@ -617,157 +616,6 @@ int CommandListener::FstrimCmd::runCommand(SocketClient *cli,
|
|||
return sendGenericOkFail(cli, 0);
|
||||
}
|
||||
|
||||
static size_t kAppFuseMaxMountPointName = 32;
|
||||
|
||||
static android::status_t getMountPath(uid_t uid, const std::string& name, std::string* path) {
|
||||
if (name.size() > kAppFuseMaxMountPointName) {
|
||||
LOG(ERROR) << "AppFuse mount name is too long.";
|
||||
return -EINVAL;
|
||||
}
|
||||
for (size_t i = 0; i < name.size(); i++) {
|
||||
if (!isalnum(name[i])) {
|
||||
LOG(ERROR) << "AppFuse mount name contains invalid character.";
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
*path = android::base::StringPrintf("/mnt/appfuse/%d_%s", uid, name.c_str());
|
||||
return android::OK;
|
||||
}
|
||||
|
||||
static android::status_t mountInNamespace(uid_t uid, int device_fd, const std::string& path) {
|
||||
// Remove existing mount.
|
||||
android::vold::ForceUnmount(path);
|
||||
|
||||
const auto opts = android::base::StringPrintf(
|
||||
"fd=%i,"
|
||||
"rootmode=40000,"
|
||||
"default_permissions,"
|
||||
"allow_other,"
|
||||
"user_id=%d,group_id=%d,"
|
||||
"context=\"u:object_r:app_fuse_file:s0\","
|
||||
"fscontext=u:object_r:app_fusefs:s0",
|
||||
device_fd,
|
||||
uid,
|
||||
uid);
|
||||
|
||||
const int result = TEMP_FAILURE_RETRY(mount(
|
||||
"/dev/fuse", path.c_str(), "fuse",
|
||||
MS_NOSUID | MS_NODEV | MS_NOEXEC | MS_NOATIME, opts.c_str()));
|
||||
if (result != 0) {
|
||||
PLOG(ERROR) << "Failed to mount " << path;
|
||||
return -errno;
|
||||
}
|
||||
|
||||
return android::OK;
|
||||
}
|
||||
|
||||
static android::status_t runCommandInNamespace(const std::string& command,
|
||||
uid_t uid,
|
||||
pid_t pid,
|
||||
const std::string& path,
|
||||
int device_fd) {
|
||||
if (DEBUG_APPFUSE) {
|
||||
LOG(DEBUG) << "Run app fuse command " << command << " for the path " << path
|
||||
<< " in namespace " << uid;
|
||||
}
|
||||
|
||||
unique_fd dir(open("/proc", O_RDONLY | O_DIRECTORY | O_CLOEXEC));
|
||||
if (dir.get() == -1) {
|
||||
PLOG(ERROR) << "Failed to open /proc";
|
||||
return -errno;
|
||||
}
|
||||
|
||||
// Obtains process file descriptor.
|
||||
const std::string pid_str = android::base::StringPrintf("%d", pid);
|
||||
const unique_fd pid_fd(
|
||||
openat(dir.get(), pid_str.c_str(), O_RDONLY | O_DIRECTORY | O_CLOEXEC));
|
||||
if (pid_fd.get() == -1) {
|
||||
PLOG(ERROR) << "Failed to open /proc/" << pid;
|
||||
return -errno;
|
||||
}
|
||||
|
||||
// Check UID of process.
|
||||
{
|
||||
struct stat sb;
|
||||
const int result = fstat(pid_fd.get(), &sb);
|
||||
if (result == -1) {
|
||||
PLOG(ERROR) << "Failed to stat /proc/" << pid;
|
||||
return -errno;
|
||||
}
|
||||
if (sb.st_uid != AID_SYSTEM) {
|
||||
LOG(ERROR) << "Only system can mount appfuse. UID expected=" << AID_SYSTEM
|
||||
<< ", actual=" << sb.st_uid;
|
||||
return -EPERM;
|
||||
}
|
||||
}
|
||||
|
||||
// Matches so far, but refuse to touch if in root namespace
|
||||
{
|
||||
char rootName[PATH_MAX];
|
||||
char pidName[PATH_MAX];
|
||||
const int root_result =
|
||||
android::vold::SaneReadLinkAt(dir.get(), "1/ns/mnt", rootName, PATH_MAX);
|
||||
const int pid_result =
|
||||
android::vold::SaneReadLinkAt(pid_fd.get(), "ns/mnt", pidName, PATH_MAX);
|
||||
if (root_result == -1) {
|
||||
LOG(ERROR) << "Failed to readlink for /proc/1/ns/mnt";
|
||||
return -EPERM;
|
||||
}
|
||||
if (pid_result == -1) {
|
||||
LOG(ERROR) << "Failed to readlink for /proc/" << pid << "/ns/mnt";
|
||||
return -EPERM;
|
||||
}
|
||||
if (!strcmp(rootName, pidName)) {
|
||||
LOG(ERROR) << "Don't mount appfuse in root namespace";
|
||||
return -EPERM;
|
||||
}
|
||||
}
|
||||
|
||||
// We purposefully leave the namespace open across the fork
|
||||
unique_fd ns_fd(openat(pid_fd.get(), "ns/mnt", O_RDONLY)); // not O_CLOEXEC
|
||||
if (ns_fd.get() < 0) {
|
||||
PLOG(ERROR) << "Failed to open namespace for /proc/" << pid << "/ns/mnt";
|
||||
return -errno;
|
||||
}
|
||||
|
||||
int child = fork();
|
||||
if (child == 0) {
|
||||
if (setns(ns_fd.get(), CLONE_NEWNS) != 0) {
|
||||
PLOG(ERROR) << "Failed to setns";
|
||||
_exit(-errno);
|
||||
}
|
||||
|
||||
if (command == "mount") {
|
||||
_exit(mountInNamespace(uid, device_fd, path));
|
||||
} else if (command == "unmount") {
|
||||
// If it's just after all FD opened on mount point are closed, umount2 can fail with
|
||||
// EBUSY. To avoid the case, specify MNT_DETACH.
|
||||
if (umount2(path.c_str(), UMOUNT_NOFOLLOW | MNT_DETACH) != 0 &&
|
||||
errno != EINVAL && errno != ENOENT) {
|
||||
PLOG(ERROR) << "Failed to unmount directory.";
|
||||
_exit(-errno);
|
||||
}
|
||||
if (rmdir(path.c_str()) != 0) {
|
||||
PLOG(ERROR) << "Failed to remove the mount directory.";
|
||||
_exit(-errno);
|
||||
}
|
||||
_exit(android::OK);
|
||||
} else {
|
||||
LOG(ERROR) << "Unknown appfuse command " << command;
|
||||
_exit(-EPERM);
|
||||
}
|
||||
}
|
||||
|
||||
if (child == -1) {
|
||||
PLOG(ERROR) << "Failed to folk child process";
|
||||
return -errno;
|
||||
}
|
||||
|
||||
android::status_t status;
|
||||
TEMP_FAILURE_RETRY(waitpid(child, &status, 0));
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
CommandListener::AppFuseCmd::AppFuseCmd() : VoldCommand("appfuse") {}
|
||||
|
||||
|
@ -777,66 +625,32 @@ int CommandListener::AppFuseCmd::runCommand(SocketClient *cli, int argc, char **
|
|||
return 0;
|
||||
}
|
||||
|
||||
const std::string command(argv[1]);
|
||||
VolumeManager *vm = VolumeManager::Instance();
|
||||
std::lock_guard<std::mutex> lock(vm->getLock());
|
||||
|
||||
const std::string command(argv[1]);
|
||||
if (command == "mount" && argc == 5) {
|
||||
const uid_t uid = atoi(argv[2]);
|
||||
const pid_t pid = atoi(argv[3]);
|
||||
const std::string name(argv[4]);
|
||||
const int mountId = atoi(argv[4]);
|
||||
|
||||
// Check mount point name.
|
||||
std::string path;
|
||||
if (getMountPath(uid, name, &path) != android::OK) {
|
||||
return cli->sendMsg(ResponseCode::CommandParameterError,
|
||||
"Invalid mount point name.",
|
||||
false);
|
||||
unique_fd device_fd;
|
||||
int result = vm->mountAppFuse(uid, pid, mountId, &device_fd);
|
||||
if (result != 0) {
|
||||
return sendGenericOkFail(cli, result);
|
||||
} else {
|
||||
return sendFd(cli, device_fd.get());
|
||||
}
|
||||
|
||||
// Create directories.
|
||||
{
|
||||
const android::status_t result = android::vold::PrepareDir(path, 0700, 0, 0);
|
||||
if (result != android::OK) {
|
||||
PLOG(ERROR) << "Failed to prepare directory " << path;
|
||||
return sendGenericOkFail(cli, result);
|
||||
}
|
||||
}
|
||||
|
||||
// Open device FD.
|
||||
unique_fd device_fd(open("/dev/fuse", O_RDWR)); // not O_CLOEXEC
|
||||
if (device_fd.get() == -1) {
|
||||
PLOG(ERROR) << "Failed to open /dev/fuse";
|
||||
return sendGenericOkFail(cli, -errno);
|
||||
}
|
||||
|
||||
// Mount.
|
||||
{
|
||||
const android::status_t result =
|
||||
runCommandInNamespace(command, uid, pid, path, device_fd.get());
|
||||
if (result != android::OK) {
|
||||
return sendGenericOkFail(cli, result);
|
||||
}
|
||||
}
|
||||
|
||||
return sendFd(cli, device_fd.get());
|
||||
} else if (command == "unmount" && argc == 5) {
|
||||
const uid_t uid = atoi(argv[2]);
|
||||
const uid_t pid = atoi(argv[3]);
|
||||
const std::string name(argv[4]);
|
||||
const int mountId = atoi(argv[4]);
|
||||
|
||||
// Check mount point name.
|
||||
std::string path;
|
||||
if (getMountPath(uid, name, &path) != android::OK) {
|
||||
return cli->sendMsg(ResponseCode::CommandParameterError,
|
||||
"Invalid mount point name.",
|
||||
false);
|
||||
}
|
||||
|
||||
const android::status_t result =
|
||||
runCommandInNamespace(command, uid, pid, path, -1 /* device_fd */);
|
||||
int result = vm->unmountAppFuse(uid, pid, mountId);
|
||||
return sendGenericOkFail(cli, result);
|
||||
}
|
||||
|
||||
return cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown appfuse cmd", false);
|
||||
return cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown appfuse cmd", false);
|
||||
}
|
||||
|
||||
android::status_t CommandListener::AppFuseCmd::sendFd(SocketClient *cli, int fd) {
|
||||
|
|
|
@ -32,12 +32,18 @@
|
|||
|
||||
#include <cutils/log.h>
|
||||
|
||||
#include <android-base/logging.h>
|
||||
#include <android-base/stringprintf.h>
|
||||
#include <sysutils/SocketClient.h>
|
||||
|
||||
#include "Devmapper.h"
|
||||
|
||||
#define DEVMAPPER_BUFFER_SIZE 4096
|
||||
|
||||
using android::base::StringPrintf;
|
||||
|
||||
static const char* kVoldPrefix = "vold:";
|
||||
|
||||
int Devmapper::dumpState(SocketClient *c) {
|
||||
|
||||
char *buffer = (char *) malloc(1024 * 64);
|
||||
|
@ -130,7 +136,10 @@ void Devmapper::ioctlInit(struct dm_ioctl *io, size_t dataSize,
|
|||
}
|
||||
}
|
||||
|
||||
int Devmapper::lookupActive(const char *name, char *ubuffer, size_t len) {
|
||||
int Devmapper::lookupActive(const char *name_raw, char *ubuffer, size_t len) {
|
||||
auto name_string = StringPrintf("%s%s", kVoldPrefix, name_raw);
|
||||
const char* name = name_string.c_str();
|
||||
|
||||
char *buffer = (char *) malloc(DEVMAPPER_BUFFER_SIZE);
|
||||
if (!buffer) {
|
||||
SLOGE("Error allocating memory (%s)", strerror(errno));
|
||||
|
@ -163,8 +172,11 @@ int Devmapper::lookupActive(const char *name, char *ubuffer, size_t len) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
int Devmapper::create(const char *name, const char *loopFile, const char *key,
|
||||
int Devmapper::create(const char *name_raw, const char *loopFile, const char *key,
|
||||
unsigned long numSectors, char *ubuffer, size_t len) {
|
||||
auto name_string = StringPrintf("%s%s", kVoldPrefix, name_raw);
|
||||
const char* name = name_string.c_str();
|
||||
|
||||
char *buffer = (char *) malloc(DEVMAPPER_BUFFER_SIZE);
|
||||
if (!buffer) {
|
||||
SLOGE("Error allocating memory (%s)", strerror(errno));
|
||||
|
@ -261,7 +273,10 @@ int Devmapper::create(const char *name, const char *loopFile, const char *key,
|
|||
return 0;
|
||||
}
|
||||
|
||||
int Devmapper::destroy(const char *name) {
|
||||
int Devmapper::destroy(const char *name_raw) {
|
||||
auto name_string = StringPrintf("%s%s", kVoldPrefix, name_raw);
|
||||
const char* name = name_string.c_str();
|
||||
|
||||
char *buffer = (char *) malloc(DEVMAPPER_BUFFER_SIZE);
|
||||
if (!buffer) {
|
||||
SLOGE("Error allocating memory (%s)", strerror(errno));
|
||||
|
@ -294,6 +309,74 @@ int Devmapper::destroy(const char *name) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
int Devmapper::destroyAll() {
|
||||
char *buffer = (char *) malloc(1024 * 64);
|
||||
if (!buffer) {
|
||||
SLOGE("Error allocating memory (%s)", strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
memset(buffer, 0, (1024 * 64));
|
||||
|
||||
char *buffer2 = (char *) malloc(DEVMAPPER_BUFFER_SIZE);
|
||||
if (!buffer2) {
|
||||
SLOGE("Error allocating memory (%s)", strerror(errno));
|
||||
free(buffer);
|
||||
return -1;
|
||||
}
|
||||
|
||||
int fd;
|
||||
if ((fd = open("/dev/device-mapper", O_RDWR | O_CLOEXEC)) < 0) {
|
||||
SLOGE("Error opening devmapper (%s)", strerror(errno));
|
||||
free(buffer);
|
||||
free(buffer2);
|
||||
return -1;
|
||||
}
|
||||
|
||||
struct dm_ioctl *io = (struct dm_ioctl *) buffer;
|
||||
ioctlInit(io, (1024 * 64), NULL, 0);
|
||||
|
||||
if (ioctl(fd, DM_LIST_DEVICES, io)) {
|
||||
SLOGE("DM_LIST_DEVICES ioctl failed (%s)", strerror(errno));
|
||||
free(buffer);
|
||||
free(buffer2);
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
struct dm_name_list *n = (struct dm_name_list *) (((char *) buffer) + io->data_start);
|
||||
if (!n->dev) {
|
||||
free(buffer);
|
||||
free(buffer2);
|
||||
close(fd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
unsigned nxt = 0;
|
||||
do {
|
||||
n = (struct dm_name_list *) (((char *) n) + nxt);
|
||||
if (strncmp(n->name, kVoldPrefix, strlen(kVoldPrefix)) == 0) {
|
||||
LOG(DEBUG) << "Tearing down stale dm device named " << n->name;
|
||||
|
||||
memset(buffer2, 0, DEVMAPPER_BUFFER_SIZE);
|
||||
struct dm_ioctl *io2 = (struct dm_ioctl *) buffer2;
|
||||
ioctlInit(io2, DEVMAPPER_BUFFER_SIZE, n->name, 0);
|
||||
if (ioctl(fd, DM_DEV_REMOVE, io2)) {
|
||||
if (errno != ENXIO) {
|
||||
PLOG(WARNING) << "Failed to destroy dm device named " << n->name;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
LOG(VERBOSE) << "Found unmanaged dm device named " << n->name;
|
||||
}
|
||||
nxt = n->next;
|
||||
} while (nxt);
|
||||
|
||||
free(buffer);
|
||||
free(buffer2);
|
||||
close(fd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void *Devmapper::_align(void *ptr, unsigned int a)
|
||||
{
|
||||
unsigned long agn = --a;
|
||||
|
|
|
@ -27,6 +27,7 @@ public:
|
|||
static int create(const char *name, const char *loopFile, const char *key,
|
||||
unsigned long numSectors, char *buffer, size_t len);
|
||||
static int destroy(const char *name);
|
||||
static int destroyAll();
|
||||
static int lookupActive(const char *name, char *buffer, size_t len);
|
||||
static int dumpState(SocketClient *c);
|
||||
|
||||
|
|
53
Loop.cpp
53
Loop.cpp
|
@ -45,6 +45,8 @@
|
|||
using android::base::StringPrintf;
|
||||
using android::base::unique_fd;
|
||||
|
||||
static const char* kVoldPrefix = "vold:";
|
||||
|
||||
int Loop::dumpState(SocketClient *c) {
|
||||
int i;
|
||||
int fd;
|
||||
|
@ -87,7 +89,10 @@ int Loop::dumpState(SocketClient *c) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
int Loop::lookupActive(const char *id, char *buffer, size_t len) {
|
||||
int Loop::lookupActive(const char *id_raw, char *buffer, size_t len) {
|
||||
auto id_string = StringPrintf("%s%s", kVoldPrefix, id_raw);
|
||||
const char* id = id_string.c_str();
|
||||
|
||||
int i;
|
||||
int fd;
|
||||
char filename[256];
|
||||
|
@ -134,7 +139,10 @@ int Loop::lookupActive(const char *id, char *buffer, size_t len) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
int Loop::create(const char *id, const char *loopFile, char *loopDeviceBuffer, size_t len) {
|
||||
int Loop::create(const char *id_raw, const char *loopFile, char *loopDeviceBuffer, size_t len) {
|
||||
auto id_string = StringPrintf("%s%s", kVoldPrefix, id_raw);
|
||||
const char* id = id_string.c_str();
|
||||
|
||||
int i;
|
||||
int fd;
|
||||
char filename[256];
|
||||
|
@ -267,6 +275,14 @@ int Loop::create(const std::string& target, std::string& out_device) {
|
|||
return -errno;
|
||||
}
|
||||
|
||||
struct loop_info64 li;
|
||||
memset(&li, 0, sizeof(li));
|
||||
strlcpy((char*) li.lo_crypt_name, kVoldPrefix, LO_NAME_SIZE);
|
||||
if (ioctl(device_fd.get(), LOOP_SET_STATUS64, &li) == -1) {
|
||||
PLOG(ERROR) << "Failed to LOOP_SET_STATUS64";
|
||||
return -errno;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -289,9 +305,36 @@ int Loop::destroyByDevice(const char *loopDevice) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
int Loop::destroyByFile(const char * /*loopFile*/) {
|
||||
errno = ENOSYS;
|
||||
return -1;
|
||||
int Loop::destroyAll() {
|
||||
for (int i = 0; i < LOOP_MAX; i++) {
|
||||
auto path = StringPrintf("/dev/block/loop%d", i);
|
||||
|
||||
unique_fd fd(open(path.c_str(), O_RDWR | O_CLOEXEC));
|
||||
if (fd.get() == -1) {
|
||||
if (errno != ENOENT) {
|
||||
PLOG(WARNING) << "Failed to open " << path;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
struct loop_info64 li;
|
||||
if (ioctl(fd.get(), LOOP_GET_STATUS64, &li) < 0) {
|
||||
PLOG(WARNING) << "Failed to LOOP_GET_STATUS64 " << path;
|
||||
continue;
|
||||
}
|
||||
|
||||
char* id = (char*) li.lo_crypt_name;
|
||||
if (strncmp(id, kVoldPrefix, strlen(kVoldPrefix)) == 0) {
|
||||
LOG(DEBUG) << "Tearing down stale loop device at " << path << " named " << id;
|
||||
|
||||
if (ioctl(fd.get(), LOOP_CLR_FD, 0) < 0) {
|
||||
PLOG(WARNING) << "Failed to LOOP_CLR_FD " << path;
|
||||
}
|
||||
} else {
|
||||
LOG(VERBOSE) << "Found unmanaged loop device at " << path << " named " << id;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int Loop::createImageFile(const char *file, unsigned long numSectors) {
|
||||
|
|
2
Loop.h
2
Loop.h
|
@ -32,7 +32,7 @@ public:
|
|||
static int create(const char *id, const char *loopFile, char *loopDeviceBuffer, size_t len);
|
||||
static int create(const std::string& file, std::string& out_device);
|
||||
static int destroyByDevice(const char *loopDevice);
|
||||
static int destroyByFile(const char *loopFile);
|
||||
static int destroyAll();
|
||||
static int createImageFile(const char *file, unsigned long numSectors);
|
||||
static int resizeImageFile(const char *file, unsigned long numSectors);
|
||||
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
#define ANDROID_VOLD_MOVE_TASK_H
|
||||
|
||||
#include "Utils.h"
|
||||
#include "VolumeBase.h"
|
||||
#include "model/VolumeBase.h"
|
||||
|
||||
#include <thread>
|
||||
|
||||
|
|
|
@ -17,12 +17,14 @@
|
|||
#include "VoldNativeService.h"
|
||||
#include "VolumeManager.h"
|
||||
#include "MoveTask.h"
|
||||
#include "TrimTask.h"
|
||||
|
||||
#include <fstream>
|
||||
|
||||
#include <android-base/logging.h>
|
||||
#include <android-base/stringprintf.h>
|
||||
#include <android-base/strings.h>
|
||||
#include <fs_mgr.h>
|
||||
#include <private/android_filesystem_config.h>
|
||||
|
||||
#ifndef LOG_TAG
|
||||
|
@ -56,7 +58,7 @@ static binder::Status translate(uint32_t status) {
|
|||
if (status == 0) {
|
||||
return binder::Status::ok();
|
||||
} else {
|
||||
return binder::Status::fromExceptionCode(status);
|
||||
return binder::Status::fromServiceSpecificError(status);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -134,11 +136,14 @@ binder::Status VoldNativeService::shutdown() {
|
|||
return translate(VolumeManager::Instance()->shutdown());
|
||||
}
|
||||
|
||||
binder::Status VoldNativeService::setDebug(bool debug) {
|
||||
binder::Status VoldNativeService::mountAll() {
|
||||
ENFORCE_UID(AID_SYSTEM);
|
||||
ACQUIRE_LOCK;
|
||||
|
||||
return translate(VolumeManager::Instance()->setDebug(debug));
|
||||
struct fstab* fstab = fs_mgr_read_fstab_default();
|
||||
int res = fs_mgr_mount_all(fstab, MOUNT_MODE_DEFAULT);
|
||||
fs_mgr_free_fstab(fstab);
|
||||
return translate(res);
|
||||
}
|
||||
|
||||
binder::Status VoldNativeService::onUserAdded(int32_t userId, int32_t userSerial) {
|
||||
|
@ -169,7 +174,8 @@ binder::Status VoldNativeService::onUserStopped(int32_t userId) {
|
|||
return translate(VolumeManager::Instance()->onUserStopped(userId));
|
||||
}
|
||||
|
||||
binder::Status VoldNativeService::partition(const std::string& diskId, int32_t partitionType, int32_t ratio) {
|
||||
binder::Status VoldNativeService::partition(const std::string& diskId, int32_t partitionType,
|
||||
int32_t ratio) {
|
||||
ENFORCE_UID(AID_SYSTEM);
|
||||
ACQUIRE_LOCK;
|
||||
|
||||
|
@ -192,7 +198,8 @@ binder::Status VoldNativeService::forgetPartition(const std::string& partGuid) {
|
|||
return translate(VolumeManager::Instance()->forgetPartition(partGuid));
|
||||
}
|
||||
|
||||
binder::Status VoldNativeService::mount(const std::string& volId, int32_t mountFlags, int32_t mountUserId) {
|
||||
binder::Status VoldNativeService::mount(const std::string& volId, int32_t mountFlags,
|
||||
int32_t mountUserId) {
|
||||
ENFORCE_UID(AID_SYSTEM);
|
||||
ACQUIRE_LOCK;
|
||||
|
||||
|
@ -241,7 +248,8 @@ binder::Status VoldNativeService::benchmark(const std::string& volId, int64_t* _
|
|||
return ok();
|
||||
}
|
||||
|
||||
binder::Status VoldNativeService::moveStorage(const std::string& fromVolId, const std::string& toVolId) {
|
||||
binder::Status VoldNativeService::moveStorage(const std::string& fromVolId,
|
||||
const std::string& toVolId) {
|
||||
ENFORCE_UID(AID_SYSTEM);
|
||||
ACQUIRE_LOCK;
|
||||
|
||||
|
@ -278,5 +286,44 @@ binder::Status VoldNativeService::mkdirs(const std::string& path) {
|
|||
return translate(VolumeManager::Instance()->mkdirs(path.c_str()));
|
||||
}
|
||||
|
||||
binder::Status VoldNativeService::createObb(const std::string& sourcePath,
|
||||
const std::string& sourceKey, int32_t ownerGid, std::string* _aidl_return) {
|
||||
ENFORCE_UID(AID_SYSTEM);
|
||||
ACQUIRE_LOCK;
|
||||
|
||||
return translate(
|
||||
VolumeManager::Instance()->createObb(sourcePath, sourceKey, ownerGid, _aidl_return));
|
||||
}
|
||||
|
||||
binder::Status VoldNativeService::destroyObb(const std::string& volId) {
|
||||
ENFORCE_UID(AID_SYSTEM);
|
||||
ACQUIRE_LOCK;
|
||||
|
||||
return translate(VolumeManager::Instance()->destroyObb(volId));
|
||||
}
|
||||
|
||||
binder::Status VoldNativeService::fstrim(int32_t fstrimFlags) {
|
||||
ENFORCE_UID(AID_SYSTEM);
|
||||
ACQUIRE_LOCK;
|
||||
|
||||
(new android::vold::TrimTask(fstrimFlags))->start();
|
||||
return ok();
|
||||
}
|
||||
|
||||
binder::Status VoldNativeService::mountAppFuse(int32_t uid, int32_t pid, int32_t mountId,
|
||||
android::base::unique_fd* _aidl_return) {
|
||||
ENFORCE_UID(AID_SYSTEM);
|
||||
ACQUIRE_LOCK;
|
||||
|
||||
return translate(VolumeManager::Instance()->mountAppFuse(uid, pid, mountId, _aidl_return));
|
||||
}
|
||||
|
||||
binder::Status VoldNativeService::unmountAppFuse(int32_t uid, int32_t pid, int32_t mountId) {
|
||||
ENFORCE_UID(AID_SYSTEM);
|
||||
ACQUIRE_LOCK;
|
||||
|
||||
return translate(VolumeManager::Instance()->unmountAppFuse(uid, pid, mountId));
|
||||
}
|
||||
|
||||
} // namespace vold
|
||||
} // namespace android
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
#ifndef _VOLD_NATIVE_SERVICE_H_
|
||||
#define _VOLD_NATIVE_SERVICE_H_
|
||||
|
||||
#include <android-base/unique_fd.h>
|
||||
#include <binder/BinderService.h>
|
||||
|
||||
#include "android/os/BnVold.h"
|
||||
|
@ -32,8 +33,7 @@ public:
|
|||
|
||||
binder::Status reset();
|
||||
binder::Status shutdown();
|
||||
|
||||
binder::Status setDebug(bool debug);
|
||||
binder::Status mountAll();
|
||||
|
||||
binder::Status onUserAdded(int32_t userId, int32_t userSerial);
|
||||
binder::Status onUserRemoved(int32_t userId);
|
||||
|
@ -53,6 +53,16 @@ public:
|
|||
binder::Status remountUid(int32_t uid, int32_t remountMode);
|
||||
|
||||
binder::Status mkdirs(const std::string& path);
|
||||
|
||||
binder::Status createObb(const std::string& sourcePath, const std::string& sourceKey,
|
||||
int32_t ownerGid, std::string* _aidl_return);
|
||||
binder::Status destroyObb(const std::string& volId);
|
||||
|
||||
binder::Status fstrim(int32_t fstrimFlags);
|
||||
|
||||
binder::Status mountAppFuse(int32_t uid, int32_t pid, int32_t mountId,
|
||||
android::base::unique_fd* _aidl_return);
|
||||
binder::Status unmountAppFuse(int32_t uid, int32_t pid, int32_t mountId);
|
||||
};
|
||||
|
||||
} // namespace vold
|
||||
|
|
|
@ -48,7 +48,8 @@
|
|||
#include <private/android_filesystem_config.h>
|
||||
|
||||
#include "Benchmark.h"
|
||||
#include "EmulatedVolume.h"
|
||||
#include "model/EmulatedVolume.h"
|
||||
#include "model/ObbVolume.h"
|
||||
#include "VolumeManager.h"
|
||||
#include "NetlinkManager.h"
|
||||
#include "ResponseCode.h"
|
||||
|
@ -68,6 +69,7 @@
|
|||
+ ((number) & (~((1U << (po2)) - 1))))
|
||||
|
||||
using android::base::StringPrintf;
|
||||
using android::base::unique_fd;
|
||||
|
||||
/*
|
||||
* Path to external storage where *only* root can access ASEC image files
|
||||
|
@ -220,6 +222,7 @@ VolumeManager::VolumeManager() {
|
|||
mSavedDirtyRatio = -1;
|
||||
// set dirty ratio to 0 when UMS is active
|
||||
mUmsDirtyRatio = 0;
|
||||
mNextObbId = 0;
|
||||
}
|
||||
|
||||
VolumeManager::~VolumeManager() {
|
||||
|
@ -317,6 +320,9 @@ int VolumeManager::start() {
|
|||
// directories that we own, in case we crashed.
|
||||
unmountAll();
|
||||
|
||||
Devmapper::destroyAll();
|
||||
Loop::destroyAll();
|
||||
|
||||
// Assume that we always have an emulated volume on internal
|
||||
// storage; the framework will decide if it should be mounted.
|
||||
CHECK(mInternalEmulated == nullptr);
|
||||
|
@ -437,6 +443,11 @@ std::shared_ptr<android::vold::VolumeBase> VolumeManager::findVolume(const std::
|
|||
return vol;
|
||||
}
|
||||
}
|
||||
for (const auto& vol : mObbVolumes) {
|
||||
if (vol->getId() == id) {
|
||||
return vol;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
@ -754,7 +765,7 @@ int VolumeManager::unmountAll() {
|
|||
endmntent(fp);
|
||||
|
||||
for (const auto& path : toUnmount) {
|
||||
SLOGW("Tearing down stale mount %s", path.c_str());
|
||||
LOG(DEBUG) << "Tearing down stale mount " << path;
|
||||
android::vold::ForceUnmount(path);
|
||||
}
|
||||
|
||||
|
@ -1962,3 +1973,223 @@ int VolumeManager::mkdirs(const char* path) {
|
|||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
static size_t kAppFuseMaxMountPointName = 32;
|
||||
|
||||
static android::status_t getMountPath(uid_t uid, const std::string& name, std::string* path) {
|
||||
if (name.size() > kAppFuseMaxMountPointName) {
|
||||
LOG(ERROR) << "AppFuse mount name is too long.";
|
||||
return -EINVAL;
|
||||
}
|
||||
for (size_t i = 0; i < name.size(); i++) {
|
||||
if (!isalnum(name[i])) {
|
||||
LOG(ERROR) << "AppFuse mount name contains invalid character.";
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
*path = android::base::StringPrintf("/mnt/appfuse/%d_%s", uid, name.c_str());
|
||||
return android::OK;
|
||||
}
|
||||
|
||||
static android::status_t mountInNamespace(uid_t uid, int device_fd, const std::string& path) {
|
||||
// Remove existing mount.
|
||||
android::vold::ForceUnmount(path);
|
||||
|
||||
const auto opts = android::base::StringPrintf(
|
||||
"fd=%i,"
|
||||
"rootmode=40000,"
|
||||
"default_permissions,"
|
||||
"allow_other,"
|
||||
"user_id=%d,group_id=%d,"
|
||||
"context=\"u:object_r:app_fuse_file:s0\","
|
||||
"fscontext=u:object_r:app_fusefs:s0",
|
||||
device_fd,
|
||||
uid,
|
||||
uid);
|
||||
|
||||
const int result = TEMP_FAILURE_RETRY(mount(
|
||||
"/dev/fuse", path.c_str(), "fuse",
|
||||
MS_NOSUID | MS_NODEV | MS_NOEXEC | MS_NOATIME, opts.c_str()));
|
||||
if (result != 0) {
|
||||
PLOG(ERROR) << "Failed to mount " << path;
|
||||
return -errno;
|
||||
}
|
||||
|
||||
return android::OK;
|
||||
}
|
||||
|
||||
static android::status_t runCommandInNamespace(const std::string& command,
|
||||
uid_t uid,
|
||||
pid_t pid,
|
||||
const std::string& path,
|
||||
int device_fd) {
|
||||
if (DEBUG_APPFUSE) {
|
||||
LOG(DEBUG) << "Run app fuse command " << command << " for the path " << path
|
||||
<< " in namespace " << uid;
|
||||
}
|
||||
|
||||
unique_fd dir(open("/proc", O_RDONLY | O_DIRECTORY | O_CLOEXEC));
|
||||
if (dir.get() == -1) {
|
||||
PLOG(ERROR) << "Failed to open /proc";
|
||||
return -errno;
|
||||
}
|
||||
|
||||
// Obtains process file descriptor.
|
||||
const std::string pid_str = android::base::StringPrintf("%d", pid);
|
||||
const unique_fd pid_fd(
|
||||
openat(dir.get(), pid_str.c_str(), O_RDONLY | O_DIRECTORY | O_CLOEXEC));
|
||||
if (pid_fd.get() == -1) {
|
||||
PLOG(ERROR) << "Failed to open /proc/" << pid;
|
||||
return -errno;
|
||||
}
|
||||
|
||||
// Check UID of process.
|
||||
{
|
||||
struct stat sb;
|
||||
const int result = fstat(pid_fd.get(), &sb);
|
||||
if (result == -1) {
|
||||
PLOG(ERROR) << "Failed to stat /proc/" << pid;
|
||||
return -errno;
|
||||
}
|
||||
if (sb.st_uid != AID_SYSTEM) {
|
||||
LOG(ERROR) << "Only system can mount appfuse. UID expected=" << AID_SYSTEM
|
||||
<< ", actual=" << sb.st_uid;
|
||||
return -EPERM;
|
||||
}
|
||||
}
|
||||
|
||||
// Matches so far, but refuse to touch if in root namespace
|
||||
{
|
||||
char rootName[PATH_MAX];
|
||||
char pidName[PATH_MAX];
|
||||
const int root_result =
|
||||
android::vold::SaneReadLinkAt(dir.get(), "1/ns/mnt", rootName, PATH_MAX);
|
||||
const int pid_result =
|
||||
android::vold::SaneReadLinkAt(pid_fd.get(), "ns/mnt", pidName, PATH_MAX);
|
||||
if (root_result == -1) {
|
||||
LOG(ERROR) << "Failed to readlink for /proc/1/ns/mnt";
|
||||
return -EPERM;
|
||||
}
|
||||
if (pid_result == -1) {
|
||||
LOG(ERROR) << "Failed to readlink for /proc/" << pid << "/ns/mnt";
|
||||
return -EPERM;
|
||||
}
|
||||
if (!strcmp(rootName, pidName)) {
|
||||
LOG(ERROR) << "Don't mount appfuse in root namespace";
|
||||
return -EPERM;
|
||||
}
|
||||
}
|
||||
|
||||
// We purposefully leave the namespace open across the fork
|
||||
unique_fd ns_fd(openat(pid_fd.get(), "ns/mnt", O_RDONLY)); // not O_CLOEXEC
|
||||
if (ns_fd.get() < 0) {
|
||||
PLOG(ERROR) << "Failed to open namespace for /proc/" << pid << "/ns/mnt";
|
||||
return -errno;
|
||||
}
|
||||
|
||||
int child = fork();
|
||||
if (child == 0) {
|
||||
if (setns(ns_fd.get(), CLONE_NEWNS) != 0) {
|
||||
PLOG(ERROR) << "Failed to setns";
|
||||
_exit(-errno);
|
||||
}
|
||||
|
||||
if (command == "mount") {
|
||||
_exit(mountInNamespace(uid, device_fd, path));
|
||||
} else if (command == "unmount") {
|
||||
// If it's just after all FD opened on mount point are closed, umount2 can fail with
|
||||
// EBUSY. To avoid the case, specify MNT_DETACH.
|
||||
if (umount2(path.c_str(), UMOUNT_NOFOLLOW | MNT_DETACH) != 0 &&
|
||||
errno != EINVAL && errno != ENOENT) {
|
||||
PLOG(ERROR) << "Failed to unmount directory.";
|
||||
_exit(-errno);
|
||||
}
|
||||
if (rmdir(path.c_str()) != 0) {
|
||||
PLOG(ERROR) << "Failed to remove the mount directory.";
|
||||
_exit(-errno);
|
||||
}
|
||||
_exit(android::OK);
|
||||
} else {
|
||||
LOG(ERROR) << "Unknown appfuse command " << command;
|
||||
_exit(-EPERM);
|
||||
}
|
||||
}
|
||||
|
||||
if (child == -1) {
|
||||
PLOG(ERROR) << "Failed to folk child process";
|
||||
return -errno;
|
||||
}
|
||||
|
||||
android::status_t status;
|
||||
TEMP_FAILURE_RETRY(waitpid(child, &status, 0));
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
int VolumeManager::createObb(const std::string& sourcePath, const std::string& sourceKey,
|
||||
int32_t ownerGid, std::string* outVolId) {
|
||||
int id = mNextObbId++;
|
||||
|
||||
auto vol = std::shared_ptr<android::vold::VolumeBase>(
|
||||
new android::vold::ObbVolume(id, sourcePath, sourceKey, ownerGid));
|
||||
vol->create();
|
||||
|
||||
mObbVolumes.push_back(vol);
|
||||
*outVolId = vol->getId();
|
||||
return android::OK;
|
||||
}
|
||||
|
||||
int VolumeManager::destroyObb(const std::string& volId) {
|
||||
auto i = mObbVolumes.begin();
|
||||
while (i != mObbVolumes.end()) {
|
||||
if ((*i)->getId() == volId) {
|
||||
(*i)->destroy();
|
||||
i = mObbVolumes.erase(i);
|
||||
} else {
|
||||
++i;
|
||||
}
|
||||
}
|
||||
return android::OK;
|
||||
}
|
||||
|
||||
int VolumeManager::mountAppFuse(uid_t uid, pid_t pid, int mountId,
|
||||
android::base::unique_fd* device_fd) {
|
||||
std::string name = std::to_string(mountId);
|
||||
|
||||
// Check mount point name.
|
||||
std::string path;
|
||||
if (getMountPath(uid, name, &path) != android::OK) {
|
||||
LOG(ERROR) << "Invalid mount point name";
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Create directories.
|
||||
const android::status_t result = android::vold::PrepareDir(path, 0700, 0, 0);
|
||||
if (result != android::OK) {
|
||||
PLOG(ERROR) << "Failed to prepare directory " << path;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Open device FD.
|
||||
device_fd->reset(open("/dev/fuse", O_RDWR)); // not O_CLOEXEC
|
||||
if (device_fd->get() == -1) {
|
||||
PLOG(ERROR) << "Failed to open /dev/fuse";
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Mount.
|
||||
return runCommandInNamespace("mount", uid, pid, path, device_fd->get());
|
||||
}
|
||||
|
||||
int VolumeManager::unmountAppFuse(uid_t uid, pid_t pid, int mountId) {
|
||||
std::string name = std::to_string(mountId);
|
||||
|
||||
// Check mount point name.
|
||||
std::string path;
|
||||
if (getMountPath(uid, name, &path) != android::OK) {
|
||||
LOG(ERROR) << "Invalid mount point name";
|
||||
return -1;
|
||||
}
|
||||
|
||||
return runCommandInNamespace("unmount", uid, pid, path, -1 /* device_fd */);
|
||||
}
|
||||
|
|
|
@ -29,18 +29,21 @@
|
|||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
|
||||
#include <android-base/unique_fd.h>
|
||||
#include <cutils/multiuser.h>
|
||||
#include <utils/List.h>
|
||||
#include <utils/Timers.h>
|
||||
#include <sysutils/SocketListener.h>
|
||||
#include <sysutils/NetlinkEvent.h>
|
||||
|
||||
#include "Disk.h"
|
||||
#include "VolumeBase.h"
|
||||
#include "model/Disk.h"
|
||||
#include "model/VolumeBase.h"
|
||||
|
||||
/* The length of an MD5 hash when encoded into ASCII hex characters */
|
||||
#define MD5_ASCII_LENGTH_PLUS_NULL ((MD5_DIGEST_LENGTH*2)+1)
|
||||
|
||||
#define DEBUG_APPFUSE 0
|
||||
|
||||
typedef enum { ASEC, OBB } container_type_t;
|
||||
|
||||
class ContainerData {
|
||||
|
@ -198,6 +201,13 @@ public:
|
|||
*/
|
||||
int mkdirs(const char* path);
|
||||
|
||||
int createObb(const std::string& path, const std::string& key, int32_t ownerGid,
|
||||
std::string* outVolId);
|
||||
int destroyObb(const std::string& volId);
|
||||
|
||||
int mountAppFuse(uid_t uid, pid_t pid, int mountId, android::base::unique_fd* device_fd);
|
||||
int unmountAppFuse(uid_t uid, pid_t pid, int mountId);
|
||||
|
||||
private:
|
||||
VolumeManager();
|
||||
void readInitialState();
|
||||
|
@ -211,6 +221,7 @@ private:
|
|||
|
||||
std::list<std::shared_ptr<DiskSource>> mDiskSources;
|
||||
std::list<std::shared_ptr<android::vold::Disk>> mDisks;
|
||||
std::list<std::shared_ptr<android::vold::VolumeBase>> mObbVolumes;
|
||||
|
||||
std::unordered_map<userid_t, int> mAddedUsers;
|
||||
std::unordered_set<userid_t> mStartedUsers;
|
||||
|
@ -219,6 +230,8 @@ private:
|
|||
std::shared_ptr<android::vold::Disk> mVirtualDisk;
|
||||
std::shared_ptr<android::vold::VolumeBase> mInternalEmulated;
|
||||
std::shared_ptr<android::vold::VolumeBase> mPrimary;
|
||||
|
||||
int mNextObbId;
|
||||
};
|
||||
|
||||
extern "C" {
|
||||
|
|
|
@ -20,8 +20,7 @@ package android.os;
|
|||
interface IVold {
|
||||
void reset();
|
||||
void shutdown();
|
||||
|
||||
void setDebug(boolean debug);
|
||||
void mountAll();
|
||||
|
||||
void onUserAdded(int userId, int userSerial);
|
||||
void onUserRemoved(int userId);
|
||||
|
@ -42,6 +41,18 @@ interface IVold {
|
|||
|
||||
void mkdirs(@utf8InCpp String path);
|
||||
|
||||
@utf8InCpp String createObb(@utf8InCpp String sourcePath,
|
||||
@utf8InCpp String sourceKey, int ownerGid);
|
||||
void destroyObb(@utf8InCpp String volId);
|
||||
|
||||
void fstrim(int fstrimFlags);
|
||||
|
||||
FileDescriptor mountAppFuse(int uid, int pid, int mountId);
|
||||
void unmountAppFuse(int uid, int pid, int mountId);
|
||||
|
||||
const int FSTRIM_FLAG_DEEP_TRIM = 1;
|
||||
const int FSTRIM_FLAG_BENCHMARK_AFTER = 2;
|
||||
|
||||
const int MOUNT_FLAG_PRIMARY = 1;
|
||||
const int MOUNT_FLAG_VISIBLE = 2;
|
||||
|
||||
|
|
2
main.cpp
2
main.cpp
|
@ -14,7 +14,7 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "Disk.h"
|
||||
#include "model/Disk.h"
|
||||
#include "VolumeManager.h"
|
||||
#include "CommandListener.h"
|
||||
#include "CryptCommandListener.h"
|
||||
|
|
130
model/ObbVolume.cpp
Normal file
130
model/ObbVolume.cpp
Normal file
|
@ -0,0 +1,130 @@
|
|||
/*
|
||||
* Copyright (C) 2017 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "fs/Vfat.h"
|
||||
#include "Devmapper.h"
|
||||
#include "Loop.h"
|
||||
#include "ObbVolume.h"
|
||||
#include "Utils.h"
|
||||
#include "VoldUtil.h"
|
||||
|
||||
#include <android-base/logging.h>
|
||||
#include <android-base/stringprintf.h>
|
||||
#include <android-base/unique_fd.h>
|
||||
#include <cutils/fs.h>
|
||||
#include <private/android_filesystem_config.h>
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/mount.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/sysmacros.h>
|
||||
#include <sys/wait.h>
|
||||
|
||||
using android::base::StringPrintf;
|
||||
using android::base::unique_fd;
|
||||
|
||||
namespace android {
|
||||
namespace vold {
|
||||
|
||||
ObbVolume::ObbVolume(int id, const std::string& sourcePath, const std::string& sourceKey,
|
||||
gid_t ownerGid) : VolumeBase(Type::kObb) {
|
||||
setId(StringPrintf("obb:%d", id));
|
||||
mSourcePath = sourcePath;
|
||||
mSourceKey = sourceKey;
|
||||
mOwnerGid = ownerGid;
|
||||
}
|
||||
|
||||
ObbVolume::~ObbVolume() {
|
||||
}
|
||||
|
||||
status_t ObbVolume::doCreate() {
|
||||
if (Loop::create(mSourcePath, mLoopPath)) {
|
||||
PLOG(ERROR) << getId() << " failed to create loop";
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!mSourceKey.empty()) {
|
||||
unsigned long nr_sec = 0;
|
||||
{
|
||||
unique_fd loop_fd(open(mLoopPath.c_str(), O_RDWR | O_CLOEXEC));
|
||||
if (loop_fd.get() == -1) {
|
||||
PLOG(ERROR) << getId() << " failed to open loop";
|
||||
return -1;
|
||||
}
|
||||
|
||||
get_blkdev_size(loop_fd.get(), &nr_sec);
|
||||
if (nr_sec == 0) {
|
||||
PLOG(ERROR) << getId() << " failed to get loop size";
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
char tmp[PATH_MAX];
|
||||
if (Devmapper::create(getId().c_str(), mLoopPath.c_str(), mSourceKey.c_str(), nr_sec,
|
||||
tmp, PATH_MAX)) {
|
||||
PLOG(ERROR) << getId() << " failed to create dm";
|
||||
return -1;
|
||||
}
|
||||
mDmPath = tmp;
|
||||
mMountPath = mDmPath;
|
||||
} else {
|
||||
mMountPath = mLoopPath;
|
||||
}
|
||||
return OK;
|
||||
}
|
||||
|
||||
status_t ObbVolume::doDestroy() {
|
||||
if (!mDmPath.empty() && Devmapper::destroy(getId().c_str())) {
|
||||
PLOG(WARNING) << getId() << " failed to destroy dm";
|
||||
}
|
||||
if (!mLoopPath.empty() && Loop::destroyByDevice(mLoopPath.c_str())) {
|
||||
PLOG(WARNING) << getId() << " failed to destroy loop";
|
||||
}
|
||||
mDmPath.clear();
|
||||
mLoopPath.clear();
|
||||
return OK;
|
||||
}
|
||||
|
||||
status_t ObbVolume::doMount() {
|
||||
auto path = StringPrintf("/mnt/obb/%s", getId().c_str());
|
||||
setPath(path);
|
||||
|
||||
if (fs_prepare_dir(path.c_str(), 0700, AID_ROOT, AID_ROOT)) {
|
||||
PLOG(ERROR) << getId() << " failed to create mount point";
|
||||
return -1;
|
||||
}
|
||||
if (android::vold::vfat::Mount(mMountPath, path,
|
||||
true, false, true, 0, mOwnerGid, 0227, false)) {
|
||||
PLOG(ERROR) << getId() << " failed to mount";
|
||||
return -1;
|
||||
}
|
||||
return OK;
|
||||
}
|
||||
|
||||
status_t ObbVolume::doUnmount() {
|
||||
auto path = getPath();
|
||||
|
||||
KillProcessesUsingPath(path);
|
||||
ForceUnmount(path);
|
||||
rmdir(path.c_str());
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
} // namespace vold
|
||||
} // namespace android
|
57
model/ObbVolume.h
Normal file
57
model/ObbVolume.h
Normal file
|
@ -0,0 +1,57 @@
|
|||
/*
|
||||
* Copyright (C) 2017 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef ANDROID_VOLD_OBB_VOLUME_H
|
||||
#define ANDROID_VOLD_OBB_VOLUME_H
|
||||
|
||||
#include "VolumeBase.h"
|
||||
|
||||
#include <cutils/multiuser.h>
|
||||
|
||||
namespace android {
|
||||
namespace vold {
|
||||
|
||||
/*
|
||||
* OBB container.
|
||||
*/
|
||||
class ObbVolume : public VolumeBase {
|
||||
public:
|
||||
ObbVolume(int id, const std::string& sourcePath, const std::string& sourceKey,
|
||||
gid_t ownerGid);
|
||||
virtual ~ObbVolume();
|
||||
|
||||
protected:
|
||||
status_t doCreate() override;
|
||||
status_t doDestroy() override;
|
||||
status_t doMount() override;
|
||||
status_t doUnmount() override;
|
||||
|
||||
private:
|
||||
std::string mSourcePath;
|
||||
std::string mSourceKey;
|
||||
gid_t mOwnerGid;
|
||||
|
||||
std::string mLoopPath;
|
||||
std::string mDmPath;
|
||||
std::string mMountPath;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(ObbVolume);
|
||||
};
|
||||
|
||||
} // namespace vold
|
||||
} // namespace android
|
||||
|
||||
#endif
|
|
@ -5,9 +5,10 @@ include $(CLEAR_VARS)
|
|||
LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
|
||||
|
||||
LOCAL_C_INCLUDES := \
|
||||
system/core/fs_mgr/include
|
||||
system/core/fs_mgr/include \
|
||||
system/vold/
|
||||
|
||||
LOCAL_STATIC_LIBRARIES := libselinux libvold liblog libcrypto
|
||||
LOCAL_STATIC_LIBRARIES := libbase libselinux libvold liblog libcrypto
|
||||
|
||||
LOCAL_SRC_FILES := VolumeManager_test.cpp
|
||||
LOCAL_MODULE := vold_tests
|
||||
|
|
Loading…
Reference in a new issue