am 826bec79: Merge "vold: remove unnecessary code from VolumeManager::unshareVolume()"
Merge commit '826bec79ea253505813d125700a12816e2c3bc0f' into gingerbread-plus-aosp
* commit '826bec79ea253505813d125700a12816e2c3bc0f':
vold: remove unnecessary code from VolumeManager::unshareVolume()
diff --git a/Android.mk b/Android.mk
index ce1a603..e353a4f 100644
--- a/Android.mk
+++ b/Android.mk
@@ -7,38 +7,59 @@
LOCAL_PATH:= $(call my-dir)
+common_src_files := \
+ VolumeManager.cpp \
+ CommandListener.cpp \
+ VoldCommand.cpp \
+ NetlinkManager.cpp \
+ NetlinkHandler.cpp \
+ Volume.cpp \
+ DirectVolume.cpp \
+ logwrapper.c \
+ Process.cpp \
+ Fat.cpp \
+ Loop.cpp \
+ Devmapper.cpp \
+ ResponseCode.cpp \
+ Xwarp.cpp
+
+common_c_includes := \
+ $(KERNEL_HEADERS) \
+ external/openssl/include
+
+common_shared_libraries := \
+ libsysutils \
+ libcutils \
+ libdiskconfig \
+ libcrypto
+
include $(CLEAR_VARS)
-LOCAL_SRC_FILES:= \
- main.cpp \
- VolumeManager.cpp \
- CommandListener.cpp \
- VoldCommand.cpp \
- NetlinkManager.cpp \
- NetlinkHandler.cpp \
- Volume.cpp \
- DirectVolume.cpp \
- logwrapper.c \
- Process.cpp \
- Fat.cpp \
- Loop.cpp \
- Devmapper.cpp \
- ResponseCode.cpp \
- Xwarp.cpp
+LOCAL_MODULE := libvold
+
+LOCAL_SRC_FILES := $(common_src_files)
+
+LOCAL_C_INCLUDES := $(common_c_includes)
+
+LOCAL_SHARED_LIBRARIES := $(common_shared_libraries)
+
+LOCAL_MODULE_TAGS := eng tests
+
+include $(BUILD_STATIC_LIBRARY)
+
+include $(CLEAR_VARS)
LOCAL_MODULE:= vold
-LOCAL_C_INCLUDES := \
- $(KERNEL_HEADERS) \
- external/openssl/include
+LOCAL_SRC_FILES := \
+ main.cpp \
+ $(common_src_files)
+
+LOCAL_C_INCLUDES := $(common_c_includes)
LOCAL_CFLAGS :=
-LOCAL_SHARED_LIBRARIES := \
- libsysutils \
- libcutils \
- libdiskconfig \
- libcrypto
+LOCAL_SHARED_LIBRARIES := $(common_shared_libraries)
include $(BUILD_EXECUTABLE)
diff --git a/CommandListener.cpp b/CommandListener.cpp
index 917b2fa..b0fc551 100644
--- a/CommandListener.cpp
+++ b/CommandListener.cpp
@@ -41,6 +41,7 @@
registerCmd(new DumpCmd());
registerCmd(new VolumeCmd());
registerCmd(new AsecCmd());
+ registerCmd(new ObbCmd());
registerCmd(new ShareCmd());
registerCmd(new StorageCmd());
registerCmd(new XwarpCmd());
@@ -397,6 +398,70 @@
return 0;
}
+CommandListener::ObbCmd::ObbCmd() :
+ VoldCommand("obb") {
+}
+
+int CommandListener::ObbCmd::runCommand(SocketClient *cli,
+ int argc, char **argv) {
+ if (argc < 2) {
+ cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing Argument", false);
+ return 0;
+ }
+
+ VolumeManager *vm = VolumeManager::Instance();
+ int rc = 0;
+
+ if (!strcmp(argv[1], "list")) {
+ dumpArgs(argc, argv, -1);
+
+ rc = vm->listMountedObbs(cli);
+ } else if (!strcmp(argv[1], "mount")) {
+ dumpArgs(argc, argv, 3);
+ if (argc != 5) {
+ cli->sendMsg(ResponseCode::CommandSyntaxError,
+ "Usage: obb mount <filename> <key> <ownerUid>", false);
+ return 0;
+ }
+ rc = vm->mountObb(argv[2], argv[3], atoi(argv[4]));
+ } else if (!strcmp(argv[1], "unmount")) {
+ dumpArgs(argc, argv, -1);
+ if (argc < 3) {
+ cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: obb unmount <source file> [force]", false);
+ return 0;
+ }
+ bool force = false;
+ if (argc > 3 && !strcmp(argv[3], "force")) {
+ force = true;
+ }
+ rc = vm->unmountObb(argv[2], force);
+ } else if (!strcmp(argv[1], "path")) {
+ dumpArgs(argc, argv, -1);
+ if (argc != 3) {
+ cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: obb path <source file>", false);
+ return 0;
+ }
+ char path[255];
+
+ if (!(rc = vm->getObbMountPath(argv[2], path, sizeof(path)))) {
+ cli->sendMsg(ResponseCode::AsecPathResult, path, false);
+ return 0;
+ }
+ } else {
+ dumpArgs(argc, argv, -1);
+ cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown obb cmd", false);
+ }
+
+ if (!rc) {
+ cli->sendMsg(ResponseCode::CommandOkay, "obb operation succeeded", false);
+ } else {
+ rc = ResponseCode::convertFromErrno();
+ cli->sendMsg(rc, "obb operation failed", true);
+ }
+
+ return 0;
+}
+
CommandListener::XwarpCmd::XwarpCmd() :
VoldCommand("xwarp") {
}
diff --git a/CommandListener.h b/CommandListener.h
index ca4fc97..75c7e81 100644
--- a/CommandListener.h
+++ b/CommandListener.h
@@ -56,6 +56,13 @@
int runCommand(SocketClient *c, int argc, char ** argv);
};
+ class ObbCmd : public VoldCommand {
+ public:
+ ObbCmd();
+ virtual ~ObbCmd() {}
+ int runCommand(SocketClient *c, int argc, char ** argv);
+ };
+
class StorageCmd : public VoldCommand {
public:
StorageCmd();
diff --git a/Loop.cpp b/Loop.cpp
index 374cac0..98015e2 100644
--- a/Loop.cpp
+++ b/Loop.cpp
@@ -38,7 +38,7 @@
char filename[256];
for (i = 0; i < LOOP_MAX; i++) {
- struct loop_info li;
+ struct loop_info64 li;
int rc;
sprintf(filename, "/dev/block/loop%d", i);
@@ -52,7 +52,7 @@
return -1;
}
- rc = ioctl(fd, LOOP_GET_STATUS, &li);
+ rc = ioctl(fd, LOOP_GET_STATUS64, &li);
close(fd);
if (rc < 0 && errno == ENXIO) {
continue;
@@ -64,9 +64,10 @@
return -1;
}
char *tmp = NULL;
- asprintf(&tmp, "%s %d %d:%d %lu %d:%d %d 0x%x {%s}", filename, li.lo_number,
+ asprintf(&tmp, "%s %d %lld:%lld %llu %lld:%lld %lld 0x%x {%s} {%s}", filename, li.lo_number,
MAJOR(li.lo_device), MINOR(li.lo_device), li.lo_inode, MAJOR(li.lo_rdevice),
- MINOR(li.lo_rdevice), li.lo_offset, li.lo_flags, li.lo_name);
+ MINOR(li.lo_rdevice), li.lo_offset, li.lo_flags, li.lo_crypt_name,
+ li.lo_file_name);
c->sendMsg(0, tmp, false);
free(tmp);
}
@@ -81,7 +82,7 @@
memset(buffer, 0, len);
for (i = 0; i < LOOP_MAX; i++) {
- struct loop_info li;
+ struct loop_info64 li;
int rc;
sprintf(filename, "/dev/block/loop%d", i);
@@ -95,7 +96,7 @@
return -1;
}
- rc = ioctl(fd, LOOP_GET_STATUS, &li);
+ rc = ioctl(fd, LOOP_GET_STATUS64, &li);
close(fd);
if (rc < 0 && errno == ENXIO) {
continue;
@@ -106,7 +107,7 @@
strerror(errno));
return -1;
}
- if (!strncmp(li.lo_name, id, LO_NAME_SIZE)) {
+ if (!strncmp((const char*) li.lo_crypt_name, id, LO_NAME_SIZE)) {
break;
}
}
@@ -184,12 +185,13 @@
return -1;
}
- struct loop_info li;
+ struct loop_info64 li;
memset(&li, 0, sizeof(li));
- strncpy(li.lo_name, id, LO_NAME_SIZE);
+ strncpy((char*) li.lo_crypt_name, id, LO_NAME_SIZE);
+ strncpy((char*) li.lo_file_name, loopFile, LO_NAME_SIZE);
- if (ioctl(fd, LOOP_SET_STATUS, &li) < 0) {
+ if (ioctl(fd, LOOP_SET_STATUS64, &li) < 0) {
SLOGE("Error setting loopback status (%s)", strerror(errno));
close(file_fd);
close(fd);
diff --git a/NetlinkHandler.cpp b/NetlinkHandler.cpp
index 818db81..f47d364 100644
--- a/NetlinkHandler.cpp
+++ b/NetlinkHandler.cpp
@@ -54,6 +54,8 @@
vm->handleBlockEvent(evt);
} else if (!strcmp(subsys, "switch")) {
vm->handleSwitchEvent(evt);
+ } else if (!strcmp(subsys, "usb_composite")) {
+ vm->handleUsbCompositeEvent(evt);
} else if (!strcmp(subsys, "battery")) {
} else if (!strcmp(subsys, "power_supply")) {
}
diff --git a/Volume.cpp b/Volume.cpp
index 2f3cad5..f945b15 100644
--- a/Volume.cpp
+++ b/Volume.cpp
@@ -73,6 +73,11 @@
*/
const char *Volume::ASECDIR = "/mnt/asec";
+/*
+ * Path to where OBBs are mounted
+ */
+const char *Volume::LOOPDIR = "/mnt/obb";
+
static const char *stateToStr(int state) {
if (state == Volume::State_Init)
return "Initializing";
diff --git a/Volume.h b/Volume.h
index 290b66d..383c2e4 100644
--- a/Volume.h
+++ b/Volume.h
@@ -44,6 +44,8 @@
static const char *SEC_ASECDIR;
static const char *ASECDIR;
+ static const char *LOOPDIR;
+
protected:
char *mLabel;
char *mMountpoint;
diff --git a/VolumeManager.cpp b/VolumeManager.cpp
index 2ff5527..87b070a 100644
--- a/VolumeManager.cpp
+++ b/VolumeManager.cpp
@@ -55,7 +55,43 @@
mVolumes = new VolumeCollection();
mActiveContainers = new AsecIdCollection();
mBroadcaster = NULL;
- mUsbMassStorageConnected = false;
+ mUsbMassStorageEnabled = false;
+ mUsbConnected = false;
+
+ readInitialState();
+}
+
+void VolumeManager::readInitialState() {
+ FILE *fp;
+ char state[255];
+
+ /*
+ * Read the initial mass storage enabled state
+ */
+ if ((fp = fopen("/sys/devices/virtual/usb_composite/usb_mass_storage/enable", "r"))) {
+ if (fgets(state, sizeof(state), fp)) {
+ mUsbMassStorageEnabled = !strncmp(state, "1", 1);
+ } else {
+ SLOGE("Failed to read usb_mass_storage enabled state (%s)", strerror(errno));
+ }
+ fclose(fp);
+ } else {
+ SLOGD("USB mass storage support is not enabled in the kernel");
+ }
+
+ /*
+ * Read the initial USB connected state
+ */
+ if ((fp = fopen("/sys/devices/virtual/switch/usb_configuration/state", "r"))) {
+ if (fgets(state, sizeof(state), fp)) {
+ mUsbConnected = !strncmp(state, "1", 1);
+ } else {
+ SLOGE("Failed to read usb_configuration switch (%s)", strerror(errno));
+ }
+ fclose(fp);
+ } else {
+ SLOGD("usb_configuration switch is not enabled in the kernel");
+ }
}
VolumeManager::~VolumeManager() {
@@ -63,26 +99,34 @@
delete mActiveContainers;
}
-#define MD5_ASCII_LENGTH ((MD5_DIGEST_LENGTH*2)+1)
-
char *VolumeManager::asecHash(const char *id, char *buffer, size_t len) {
+ static const char* digits = "0123456789abcdef";
+
unsigned char sig[MD5_DIGEST_LENGTH];
- if (len < MD5_ASCII_LENGTH) {
- SLOGE("Target hash buffer size < %d bytes (%d)", MD5_ASCII_LENGTH, len);
+ if (buffer == NULL) {
+ SLOGE("Destination buffer is NULL");
+ errno = ESPIPE;
+ return NULL;
+ } else if (id == NULL) {
+ SLOGE("Source buffer is NULL");
+ errno = ESPIPE;
+ return NULL;
+ } else if (len < MD5_ASCII_LENGTH_PLUS_NULL) {
+ SLOGE("Target hash buffer size < %d bytes (%d)",
+ MD5_ASCII_LENGTH_PLUS_NULL, len);
errno = ESPIPE;
return NULL;
}
MD5(reinterpret_cast<const unsigned char*>(id), strlen(id), sig);
- memset(buffer, 0, len);
-
+ char *p = buffer;
for (int i = 0; i < MD5_DIGEST_LENGTH; i++) {
- char tmp[3];
- snprintf(tmp, 3, "%.02x", sig[i]);
- strcat(buffer, tmp);
+ *p++ = digits[sig[i] >> 4];
+ *p++ = digits[sig[i] & 0x0F];
}
+ *p = '\0';
return buffer;
}
@@ -108,17 +152,12 @@
return 0;
}
-void VolumeManager::notifyUmsConnected(bool connected) {
+void VolumeManager::notifyUmsAvailable(bool available) {
char msg[255];
- if (connected) {
- mUsbMassStorageConnected = true;
- } else {
- mUsbMassStorageConnected = false;
- }
snprintf(msg, sizeof(msg), "Share method ums now %s",
- (connected ? "available" : "unavailable"));
-
+ (available ? "available" : "unavailable"));
+ SLOGD(msg);
getBroadcaster()->sendBroadcast(ResponseCode::ShareAvailabilityChange,
msg, false);
}
@@ -133,17 +172,37 @@
return;
}
- if (!strcmp(name, "usb_mass_storage")) {
-
- if (!strcmp(state, "online")) {
- notifyUmsConnected(true);
- } else {
- notifyUmsConnected(false);
+ bool oldAvailable = massStorageAvailable();
+ if (!strcmp(name, "usb_configuration")) {
+ mUsbConnected = !strcmp(state, "1");
+ SLOGD("USB %s", mUsbConnected ? "connected" : "disconnected");
+ bool newAvailable = massStorageAvailable();
+ if (newAvailable != oldAvailable) {
+ notifyUmsAvailable(newAvailable);
}
} else {
SLOGW("Ignoring unknown switch '%s'", name);
}
}
+void VolumeManager::handleUsbCompositeEvent(NetlinkEvent *evt) {
+ const char *function = evt->findParam("FUNCTION");
+ const char *enabled = evt->findParam("ENABLED");
+
+ if (!function || !enabled) {
+ SLOGW("usb_composite event missing function/enabled info");
+ return;
+ }
+
+ if (!strcmp(function, "usb_mass_storage")) {
+ bool oldAvailable = massStorageAvailable();
+ mUsbMassStorageEnabled = !strcmp(enabled, "1");
+ SLOGD("usb_mass_storage function %s", mUsbMassStorageEnabled ? "enabled" : "disabled");
+ bool newAvailable = massStorageAvailable();
+ if (newAvailable != oldAvailable) {
+ notifyUmsAvailable(newAvailable);
+ }
+ }
+}
void VolumeManager::handleBlockEvent(NetlinkEvent *evt) {
const char *devpath = evt->findParam("DEVPATH");
@@ -194,6 +253,24 @@
return v->formatVol();
}
+int VolumeManager::getObbMountPath(const char *sourceFile, char *mountPath, int mountPathLen) {
+ char idHash[33];
+ if (!asecHash(sourceFile, idHash, sizeof(idHash))) {
+ SLOGE("Hash of '%s' failed (%s)", sourceFile, strerror(errno));
+ return -1;
+ }
+
+ memset(mountPath, 0, mountPathLen);
+ snprintf(mountPath, mountPathLen, "%s/%s", Volume::LOOPDIR, idHash);
+
+ if (access(mountPath, F_OK)) {
+ errno = ENOENT;
+ return -1;
+ }
+
+ return 0;
+}
+
int VolumeManager::getAsecMountPath(const char *id, char *buffer, int maxlen) {
char asecFileName[255];
snprintf(asecFileName, sizeof(asecFileName), "%s/%s.asec", Volume::SEC_ASECDIR, id);
@@ -446,7 +523,8 @@
return -1;
}
-#define ASEC_UNMOUNT_RETRIES 5
+#define UNMOUNT_RETRIES 5
+#define UNMOUNT_SLEEP_BETWEEN_RETRY_MS (1000 * 1000)
int VolumeManager::unmountAsec(const char *id, bool force) {
char asecFileName[255];
char mountPoint[255];
@@ -460,37 +538,56 @@
return -1;
}
+ return unmountLoopImage(id, idHash, asecFileName, mountPoint, force);
+}
+
+int VolumeManager::unmountObb(const char *fileName, bool force) {
+ char mountPoint[255];
+
+ char idHash[33];
+ if (!asecHash(fileName, idHash, sizeof(idHash))) {
+ SLOGE("Hash of '%s' failed (%s)", fileName, strerror(errno));
+ return -1;
+ }
+
+ snprintf(mountPoint, sizeof(mountPoint), "%s/%s", Volume::LOOPDIR, idHash);
+
+ return unmountLoopImage(fileName, idHash, fileName, mountPoint, force);
+}
+
+int VolumeManager::unmountLoopImage(const char *id, const char *idHash,
+ const char *fileName, const char *mountPoint, bool force) {
if (!isMountpointMounted(mountPoint)) {
- SLOGE("Unmount request for ASEC %s when not mounted", id);
+ SLOGE("Unmount request for %s when not mounted", id);
errno = EINVAL;
return -1;
}
int i, rc;
- for (i = 1; i <= ASEC_UNMOUNT_RETRIES; i++) {
+ for (i = 1; i <= UNMOUNT_RETRIES; i++) {
rc = umount(mountPoint);
if (!rc) {
break;
}
if (rc && (errno == EINVAL || errno == ENOENT)) {
- SLOGI("Secure container %s unmounted OK", id);
+ SLOGI("Container %s unmounted OK", id);
rc = 0;
break;
}
- SLOGW("ASEC %s unmount attempt %d failed (%s)",
+ SLOGW("%s unmount attempt %d failed (%s)",
id, i, strerror(errno));
int action = 0; // default is to just complain
if (force) {
- if (i > (ASEC_UNMOUNT_RETRIES - 2))
+ if (i > (UNMOUNT_RETRIES - 2))
action = 2; // SIGKILL
- else if (i > (ASEC_UNMOUNT_RETRIES - 3))
+ else if (i > (UNMOUNT_RETRIES - 3))
action = 1; // SIGHUP
}
Process::killProcessesWithOpenFiles(mountPoint, action);
- usleep(1000 * 1000);
+ usleep(UNMOUNT_SLEEP_BETWEEN_RETRY_MS);
}
if (rc) {
@@ -507,7 +604,7 @@
}
SLOGW("Failed to rmdir %s (%s)", mountPoint, strerror(errno));
- usleep(1000 * 1000);
+ usleep(UNMOUNT_SLEEP_BETWEEN_RETRY_MS);
}
if (!retries) {
@@ -522,7 +619,7 @@
if (!Loop::lookupActive(idHash, loopDevice, sizeof(loopDevice))) {
Loop::destroyByDevice(loopDevice);
} else {
- SLOGW("Failed to find loop device for {%s} (%s)", asecFileName, strerror(errno));
+ SLOGW("Failed to find loop device for {%s} (%s)", fileName, strerror(errno));
}
AsecIdCollection::iterator it;
@@ -700,6 +797,110 @@
return 0;
}
+/**
+ * Mounts an image file <code>img</code>.
+ */
+int VolumeManager::mountObb(const char *img, const char *key, int ownerUid) {
+ char mountPoint[255];
+
+ char idHash[33];
+ if (!asecHash(img, idHash, sizeof(idHash))) {
+ SLOGE("Hash of '%s' failed (%s)", img, strerror(errno));
+ return -1;
+ }
+
+ snprintf(mountPoint, sizeof(mountPoint), "%s/%s", Volume::LOOPDIR, idHash);
+
+ if (isMountpointMounted(mountPoint)) {
+ SLOGE("Image %s already mounted", img);
+ errno = EBUSY;
+ return -1;
+ }
+
+ char loopDevice[255];
+ if (Loop::lookupActive(idHash, loopDevice, sizeof(loopDevice))) {
+ if (Loop::create(idHash, img, loopDevice, sizeof(loopDevice))) {
+ SLOGE("Image loop device creation failed (%s)", strerror(errno));
+ return -1;
+ }
+ if (mDebug) {
+ SLOGD("New loop device created at %s", loopDevice);
+ }
+ } else {
+ if (mDebug) {
+ SLOGD("Found active loopback for %s at %s", img, loopDevice);
+ }
+ }
+
+ char dmDevice[255];
+ bool cleanupDm = false;
+ int fd;
+ unsigned int nr_sec = 0;
+
+ if ((fd = open(loopDevice, O_RDWR)) < 0) {
+ SLOGE("Failed to open loopdevice (%s)", strerror(errno));
+ Loop::destroyByDevice(loopDevice);
+ return -1;
+ }
+
+ if (ioctl(fd, BLKGETSIZE, &nr_sec)) {
+ SLOGE("Failed to get loop size (%s)", strerror(errno));
+ Loop::destroyByDevice(loopDevice);
+ close(fd);
+ return -1;
+ }
+
+ close(fd);
+
+ if (strcmp(key, "none")) {
+ if (Devmapper::lookupActive(idHash, dmDevice, sizeof(dmDevice))) {
+ if (Devmapper::create(idHash, loopDevice, key, nr_sec,
+ dmDevice, sizeof(dmDevice))) {
+ SLOGE("ASEC device mapping failed (%s)", strerror(errno));
+ Loop::destroyByDevice(loopDevice);
+ return -1;
+ }
+ if (mDebug) {
+ SLOGD("New devmapper instance created at %s", dmDevice);
+ }
+ } else {
+ if (mDebug) {
+ SLOGD("Found active devmapper for %s at %s", img, dmDevice);
+ }
+ }
+ cleanupDm = true;
+ } else {
+ strcpy(dmDevice, loopDevice);
+ }
+
+ if (mkdir(mountPoint, 0755)) {
+ if (errno != EEXIST) {
+ SLOGE("Mountpoint creation failed (%s)", strerror(errno));
+ if (cleanupDm) {
+ Devmapper::destroy(idHash);
+ }
+ Loop::destroyByDevice(loopDevice);
+ return -1;
+ }
+ }
+
+ if (Fat::doMount(dmDevice, mountPoint, true, false, ownerUid, 0,
+ 0227, false)) {
+ SLOGE("Image mount failed (%s)", strerror(errno));
+ if (cleanupDm) {
+ Devmapper::destroy(idHash);
+ }
+ Loop::destroyByDevice(loopDevice);
+ return -1;
+ }
+
+ mActiveContainers->push_back(strdup(img));
+ if (mDebug) {
+ SLOGD("Image %s mounted", img);
+ }
+ return 0;
+}
+
int VolumeManager::mountVolume(const char *label) {
Volume *v = lookupVolume(label);
@@ -711,6 +912,51 @@
return v->mountVol();
}
+int VolumeManager::listMountedObbs(SocketClient* cli) {
+ char device[256];
+ char mount_path[256];
+ char rest[256];
+ FILE *fp;
+ char line[1024];
+
+ if (!(fp = fopen("/proc/mounts", "r"))) {
+ SLOGE("Error opening /proc/mounts (%s)", strerror(errno));
+ return -1;
+ }
+
+ // Create a string to compare against that has a trailing slash
+ int loopDirLen = sizeof(Volume::LOOPDIR);
+ char loopDir[loopDirLen + 2];
+ strcpy(loopDir, Volume::LOOPDIR);
+ loopDir[loopDirLen++] = '/';
+ loopDir[loopDirLen] = '\0';
+
+ while(fgets(line, sizeof(line), fp)) {
+ line[strlen(line)-1] = '\0';
+
+ /*
+ * Should look like:
+ * /dev/block/loop0 /mnt/obb/fc99df1323fd36424f864dcb76b76d65 ...
+ */
+ sscanf(line, "%255s %255s %255s\n", device, mount_path, rest);
+
+ if (!strncmp(mount_path, loopDir, loopDirLen)) {
+ int fd = open(device, O_RDONLY);
+ if (fd >= 0) {
+ struct loop_info64 li;
+ if (ioctl(fd, LOOP_GET_STATUS64, &li) >= 0) {
+ cli->sendMsg(ResponseCode::AsecListResult,
+ (const char*) li.lo_file_name, false);
+ }
+ close(fd);
+ }
+ }
+ }
+
+ fclose(fp);
+ return 0;
+}
+
int VolumeManager::shareAvailable(const char *method, bool *avail) {
if (strcmp(method, "ums")) {
@@ -718,10 +964,7 @@
return -1;
}
- if (mUsbMassStorageConnected)
- *avail = true;
- else
- *avail = false;
+ *avail = massStorageAvailable();
return 0;
}
@@ -750,9 +993,9 @@
if (!strcmp(cmd, "ums")) {
if (!strcmp(arg, "connect")) {
- notifyUmsConnected(true);
+ notifyUmsAvailable(true);
} else if (!strcmp(arg, "disconnect")) {
- notifyUmsConnected(false);
+ notifyUmsAvailable(false);
} else {
errno = EINVAL;
return -1;
diff --git a/VolumeManager.h b/VolumeManager.h
index 2ec9eb3..0619c73 100644
--- a/VolumeManager.h
+++ b/VolumeManager.h
@@ -24,6 +24,9 @@
#include "Volume.h"
+/* The length of an MD5 hash when encoded into ASCII hex characters */
+#define MD5_ASCII_LENGTH_PLUS_NULL ((MD5_DIGEST_LENGTH*2)+1)
+
typedef android::List<char *> AsecIdCollection;
class VolumeManager {
@@ -35,7 +38,8 @@
VolumeCollection *mVolumes;
AsecIdCollection *mActiveContainers;
- bool mUsbMassStorageConnected;
+ bool mUsbMassStorageEnabled;
+ bool mUsbConnected;
bool mDebug;
public:
@@ -46,6 +50,7 @@
void handleBlockEvent(NetlinkEvent *evt);
void handleSwitchEvent(NetlinkEvent *evt);
+ void handleUsbCompositeEvent(NetlinkEvent *evt);
int addVolume(Volume *v);
@@ -58,6 +63,8 @@
int shareEnabled(const char *path, const char *method, bool *enabled);
int simulate(const char *cmd, const char *arg);
int formatVolume(const char *label);
+
+ /* ASEC */
int createAsec(const char *id, unsigned numSectors, const char *fstype,
const char *key, int ownerUid);
int finalizeAsec(const char *id);
@@ -67,10 +74,18 @@
int renameAsec(const char *id1, const char *id2);
int getAsecMountPath(const char *id, char *buffer, int maxlen);
+ /* Loopback images */
+ int listMountedObbs(SocketClient* cli);
+ int mountObb(const char *fileName, const char *key, int ownerUid);
+ int unmountObb(const char *fileName, bool force);
+ int getObbMountPath(const char *id, char *buffer, int maxlen);
+
+ /* Shared between ASEC and Loopback images */
+ int unmountLoopImage(const char *containerId, const char *loopId,
+ const char *fileName, const char *mountPoint, bool force);
+
void setDebug(bool enable);
- // XXX: This should be moved private once switch uevents are working
- void notifyUmsConnected(bool connected);
// XXX: Post froyo this should be moved and cleaned up
int cleanupAsec(Volume *v, bool force);
@@ -83,7 +98,11 @@
private:
VolumeManager();
+ void readInitialState();
Volume *lookupVolume(const char *label);
bool isMountpointMounted(const char *mp);
+
+ inline bool massStorageAvailable() const { return mUsbMassStorageEnabled && mUsbConnected; }
+ void notifyUmsAvailable(bool available);
};
#endif
diff --git a/logwrapper.c b/logwrapper.c
index afc6cdb..4862efb 100644
--- a/logwrapper.c
+++ b/logwrapper.c
@@ -51,7 +51,7 @@
if (a == 0 && b == sizeof(buffer) - 1) {
// buffer is full, flush
buffer[b] = '\0';
- LOG(LOG_INFO, tag, &buffer[a]);
+ LOG(LOG_INFO, tag, "%s", &buffer[a]);
b = 0;
} else if (a != b) {
// Keep left-overs
@@ -67,7 +67,7 @@
// Flush remaining data
if (a != b) {
buffer[b] = '\0';
- LOG(LOG_INFO, tag, &buffer[a]);
+ LOG(LOG_INFO, tag, "%s", &buffer[a]);
}
status = 0xAAAA;
if (wait(&status) != -1) { // Wait for child
diff --git a/main.cpp b/main.cpp
index 530321c..f97632b 100644
--- a/main.cpp
+++ b/main.cpp
@@ -77,32 +77,6 @@
}
coldboot("/sys/block");
- /*
- * Switch uevents are broken.
- * For now we manually bootstrap
- * the ums switch
- */
- {
- FILE *fp;
- char state[255];
-
- if ((fp = fopen("/sys/devices/virtual/switch/usb_mass_storage/state",
- "r"))) {
- if (fgets(state, sizeof(state), fp)) {
- if (!strncmp(state, "online", 6)) {
- vm->notifyUmsConnected(true);
- } else {
- vm->notifyUmsConnected(false);
- }
- } else {
- SLOGE("Failed to read switch state (%s)", strerror(errno));
- }
-
- fclose(fp);
- } else {
- SLOGW("No UMS switch available");
- }
- }
// coldboot("/sys/class/switch");
/*
diff --git a/tests/Android.mk b/tests/Android.mk
new file mode 100644
index 0000000..8ae4b5d
--- /dev/null
+++ b/tests/Android.mk
@@ -0,0 +1,36 @@
+# Build the unit tests.
+LOCAL_PATH := $(call my-dir)
+include $(CLEAR_VARS)
+
+test_src_files := \
+ VolumeManager_test.cpp
+
+shared_libraries := \
+ liblog \
+ libstlport \
+ libcrypto
+
+static_libraries := \
+ libvold \
+ libgtest \
+ libgtest_main
+
+c_includes := \
+ external/openssl/include \
+ bionic \
+ bionic/libstdc++/include \
+ external/gtest/include \
+ external/stlport/stlport
+
+module_tags := eng tests
+
+$(foreach file,$(test_src_files), \
+ $(eval include $(CLEAR_VARS)) \
+ $(eval LOCAL_SHARED_LIBRARIES := $(shared_libraries)) \
+ $(eval LOCAL_STATIC_LIBRARIES := $(static_libraries)) \
+ $(eval LOCAL_C_INCLUDES := $(c_includes)) \
+ $(eval LOCAL_SRC_FILES := $(file)) \
+ $(eval LOCAL_MODULE := $(notdir $(file:%.cpp=%))) \
+ $(eval LOCAL_MODULE_TAGS := $(module_tags)) \
+ $(eval include $(BUILD_EXECUTABLE)) \
+)
diff --git a/tests/VolumeManager_test.cpp b/tests/VolumeManager_test.cpp
new file mode 100644
index 0000000..c0c1fa5
--- /dev/null
+++ b/tests/VolumeManager_test.cpp
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2010 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 <errno.h>
+
+#define LOG_TAG "VolumeManager_test"
+#include <utils/Log.h>
+#include <openssl/md5.h>
+#include "../VolumeManager.h"
+
+#include <gtest/gtest.h>
+
+namespace android {
+
+class VolumeManagerTest : public testing::Test {
+protected:
+ virtual void SetUp() {
+ }
+
+ virtual void TearDown() {
+ }
+};
+
+TEST_F(VolumeManagerTest, AsecHashTests) {
+ char buffer[MD5_ASCII_LENGTH_PLUS_NULL];
+ char* dst = reinterpret_cast<char*>(&buffer);
+
+ const char* src1 = "";
+ const char* exp1 = "d41d8cd98f00b204e9800998ecf8427e";
+
+ EXPECT_TRUE(VolumeManager::asecHash(exp1, (char*)NULL, sizeof(buffer)) == NULL && errno == ESPIPE)
+ << "Should return NULL and set errno to ESPIPE when destination buffer is NULL";
+ EXPECT_TRUE(VolumeManager::asecHash(exp1, dst, 0) == NULL && errno == ESPIPE)
+ << "Should return NULL and set errno to ESPIPE when destination buffer length is 0";
+ EXPECT_TRUE(VolumeManager::asecHash((const char*)NULL, dst, sizeof(buffer)) == NULL && errno == ESPIPE)
+ << "Should return NULL and set errno to ESPIPE when source buffer is NULL";
+
+ EXPECT_FALSE(VolumeManager::asecHash(src1, dst, sizeof(buffer)) == NULL)
+ << "Should not return NULL on valid source, destination, and destination size";
+ EXPECT_STREQ(exp1, dst)
+ << "MD5 summed output should match";
+
+ const char* src2 = "android";
+ const char* exp2 = "c31b32364ce19ca8fcd150a417ecce58";
+ EXPECT_FALSE(VolumeManager::asecHash(src2, dst, sizeof(buffer)) == NULL)
+ << "Should not return NULL on valid source, destination, and destination size";
+ EXPECT_STREQ(exp2, dst)
+ << "MD5 summed output should match";
+}
+
+}