aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKirsten Lee <kirstenlee@google.com>2015-07-15 16:41:37 -0700
committerKirsten Lee <kirstenlee@google.com>2015-07-17 14:38:10 -0700
commit8ac454106699a16f57a4095fe18317a74ed947e6 (patch)
treee2a4e089988db631a51b5f7116d4b101ac97eff8
parentccc67f3f00dd92210b64c610abbb93bb557ac526 (diff)
downloadqemu-8ac454106699a16f57a4095fe18317a74ed947e6.tar.gz
Making the emulator respect user-specified data partition size for API 19+
Prior to API 19, the internal partition size specified by the user was the size they saw in the corresponding AVD, but as of API 19, users see a fixed internal partition size regardless of the parameter they passed.    + Extend userdata-qemu.img to the correct size via resize2fs.  Resize2fs can be used to extend an existing data partition to the size specified in an AVD, but the underlying logical volume size needs to have enough space to allow this + Create an empty partition of the desired size for later restoration and let the emulator copy over the data inside userdata.img.  We cannot only create an empty ext4 data partition without copying as the emulator must be given the chance to move a small amount of default data from userdata.img that the user is expecting to see. Change-Id: I782a477da72b372a16c2b06c9dabfb3620f27ff6
-rw-r--r--Makefile.common1
-rw-r--r--android/ext4_resize.cpp164
-rw-r--r--android/ext4_resize.h51
-rw-r--r--vl-android.c53
4 files changed, 253 insertions, 16 deletions
diff --git a/Makefile.common b/Makefile.common
index 791ac7f035..becf3a5321 100644
--- a/Makefile.common
+++ b/Makefile.common
@@ -492,6 +492,7 @@ CORE_MISC_SOURCES = \
android/cbuffer.c \
android/charpipe.c \
android/core-init-utils.c \
+ android/ext4_resize.cpp \
android/gps.c \
android/hw-kmsg.c \
android/hw-lcd.c \
diff --git a/android/ext4_resize.cpp b/android/ext4_resize.cpp
new file mode 100644
index 0000000000..cbeb206be9
--- /dev/null
+++ b/android/ext4_resize.cpp
@@ -0,0 +1,164 @@
+// Copyright (C) 2015 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 <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#ifdef _WIN32
+#include "android/base/system/Win32Utils.h"
+#include "android/utils/win32_cmdline_quote.h"
+#include <windows.h>
+
+using android::base::Win32Utils;
+#else
+#include <sys/wait.h>
+#endif
+
+#include "android/base/String.h"
+#include "android/ext4_resize.h"
+#include "android/utils/path.h"
+#include "base/system/System.h"
+#include "main-common.h"
+
+using android::base::String;
+using android::base::System;
+
+// Convenience function for formatting and printing system call/library
+// function errors that show up regardless of host platform. Equivalent
+// to printing the stringified error code from errno or GetLastError()
+// (for windows).
+void explainSystemErrors (const char * msg) {
+#ifdef _WIN32
+ char *pstr = NULL;
+ FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM |
+ FORMAT_MESSAGE_ALLOCATE_BUFFER,
+ NULL,
+ GetLastError(),
+ 0,
+ (LPTSTR) &pstr,
+ 2,
+ NULL);
+ fprintf(stderr, "ERROR: %s - %s\n", msg, pstr);
+ LocalFree(pstr);
+#else
+ fprintf(stderr, "ERROR: %s - %s\n", msg, strerror(errno));
+#endif
+}
+
+int resizeExt4Partition (const char * partitionPath, int64_t newByteSize) {
+ // sanity checks
+ if (partitionPath == NULL || !checkExt4PartitionSize(newByteSize)) {
+ return -1;
+ }
+
+ // format common arguments once
+ String executable = System::get()->findBundledExecutable("resize2fs");
+ if(executable.empty()) {
+ fprintf(stderr, "ERROR: couldn't get path to resize2fs binary\n");
+ return -1;
+ }
+
+ char size_in_MB[50];
+ int copied = snprintf(size_in_MB, sizeof(size_in_MB),
+ "%uM", convertBytesToMB(newByteSize));
+ size_in_MB[sizeof(size_in_MB) - 1] = '\0';
+ if (copied < 0 || copied >= sizeof(size_in_MB)) {
+ fprintf(stderr, "ERROR: failed to format size in resize2fs command\n");
+ return -1;
+ }
+
+
+#ifdef _WIN32
+ STARTUPINFO startup;
+ PROCESS_INFORMATION pinfo;
+ DWORD exitCode;
+
+ ZeroMemory(&startup, sizeof(startup));
+ ZeroMemory(&pinfo, sizeof(pinfo));
+ startup.cb = sizeof(startup);
+
+ char args[PATH_MAX * 2 + 1];
+ copied = snprintf(args, sizeof(args), "resize2fs.exe -f %s %s",
+ Win32Utils::quoteCommandLine(partitionPath).c_str(),
+ size_in_MB);
+ args[sizeof(args) - 1] = '\0';
+ if (copied < 0 || copied >= sizeof(args)) {
+ fprintf(stderr, "ERROR: failed to format resize2fs command\n");
+ return -1;
+ }
+
+ BOOL success = CreateProcess(
+ Win32Utils::quoteCommandLine(executable.c_str()).c_str(), /* program path */
+ args, /* command line args */
+ NULL, /* process handle is not inheritable */
+ NULL, /* thread handle is not inheritable */
+ FALSE, /* no, don't inherit any handles */
+ CREATE_NO_WINDOW, /* the new process doesn't have a console */
+ NULL, /* use parent's environment block */
+ NULL, /* use parent's starting directory */
+ &startup, /* startup info, i.e. std handles */
+ &pinfo);
+ if (!success) {
+ explainSystemErrors("failed to create process while resizing partition");
+ return -2;
+ }
+
+ WaitForSingleObject(pinfo.hProcess, INFINITE);
+ if (!GetExitCodeProcess(pinfo.hProcess, &exitCode)) {
+ explainSystemErrors("couldn't get exit code from resizing partition process");
+ CloseHandle(pinfo.hProcess);
+ CloseHandle(pinfo.hThread);
+ return -2;
+ }
+ CloseHandle(pinfo.hProcess);
+ CloseHandle(pinfo.hThread);
+
+#else
+ int32_t exitCode = 0;
+ pid_t pid;
+ pid_t child = fork();
+
+ if (child < 0) {
+ explainSystemErrors("couldn't create a child process to resize the partition");
+ return -2;
+ }else if (child == 0) {
+ execlp(executable.c_str(), executable.c_str(), "-f", partitionPath,
+ size_in_MB, NULL);
+ exit(-1);
+ }
+
+ while ((pid = waitpid(-1, &exitCode, 0)) != child) {
+ if (pid == -1) {
+ explainSystemErrors("resizing partition waitpid failed");
+ return -2;
+ }
+ }
+#endif
+ if(exitCode != 0) {
+ fprintf(stderr, "ERROR: resizing partition failed with exit code %d\n",
+ exitCode);
+ return exitCode;
+ }
+ return 0;
+}
+
+bool checkExt4PartitionSize (int64_t byteSize) {
+ uint64_t maxSizeMB = 16 * 1024 * 1024; // (16 TiB) * (1024 GiB / TiB) * (1024 MiB / GiB)
+ uint64_t minSizeMB = 128;
+ uint64_t sizeMB = convertBytesToMB(byteSize);
+
+ //compiler converts signed to unsigned
+ return (sizeMB >= minSizeMB) && (sizeMB <= maxSizeMB);
+}
diff --git a/android/ext4_resize.h b/android/ext4_resize.h
new file mode 100644
index 0000000000..47ad5afdaa
--- /dev/null
+++ b/android/ext4_resize.h
@@ -0,0 +1,51 @@
+// Copyright (C) 2015 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_EXT4_RESIZE_H
+#define ANDROID_EXT4_RESIZE_H
+
+#include <android/base/Limits.h>
+#include <android/utils/compiler.h>
+#include <stdint.h>
+
+ANDROID_BEGIN_HEADER
+
+// Resize the partition in |partitionPath| to be newSize.
+//
+// |partitionPath| should hold the full, null-terminated path to the
+// desired partition.
+// |newByteSize| should be the desired new size of the partition in bytes,
+// no smaller than 128 MiB and no greater than 16 TiB. If the |newByteSize|
+// is below the minimum allowed for the specified partition, resize2fs will
+// still fail and the error code will be returned to the user
+//
+// Returns:
+// 0 - indicating the resize was successful
+// -1 - indicating that formatting the arguments failed
+// -2 - indicating a system call went wrong
+// Otherwise the exit code of the resize2fs process is returned.
+int resizeExt4Partition(const char * partitionPath, int64_t newByteSize);
+
+// Returns true if |byteSize| is a valid ext4 partition size; i.e. within the
+// range of 128 MiB and 16 TiB inclusive, false otherwise.
+//
+// ext4 partitions have a theoretical limit of 1 EiB, although on 32-bit
+// systems the partition limit is reduced to 16 TiB due to the data range
+// of 32-bits, so enforce 16 TiB to minimize differences between systems of
+// different bitness. The minimum size of an ext4 partition is 128 MiB.
+bool checkExt4PartitionSize (int64_t byteSize);
+
+ANDROID_END_HEADER
+
+#endif /* _ANDROID_EXT4_RESIZE_H */
diff --git a/vl-android.c b/vl-android.c
index 260da499e1..72f683db1c 100644
--- a/vl-android.c
+++ b/vl-android.c
@@ -46,24 +46,29 @@
#include "sysemu/blockdev.h"
#include "audio/audio.h"
-#include "migration/qemu-file.h"
#include "android/android.h"
+#include "android/camera/camera-service.h"
#include "android/charpipe.h"
-#include "android/log-rotate.h"
-#include "modem_driver.h"
+#include "android/display-core.h"
+#include "android/ext4_resize.h"
#include "android/filesystems/ext4_utils.h"
#include "android/filesystems/fstab_parser.h"
#include "android/filesystems/partition_types.h"
#include "android/filesystems/ramdisk_extractor.h"
+#include "android/globals.h"
#include "android/gps.h"
#include "android/hw-kmsg.h"
#include "android/hw-pipe-net.h"
#include "android/hw-qemud.h"
#include "android/hw-sensors.h"
-#include "android/camera/camera-service.h"
+#include "android/log-rotate.h"
#include "android/multitouch-port.h"
+#include "android/multitouch-screen.h"
+#include "android/opengles.h"
+#include "android/opengl/emugl_config.h"
#include "android/skin/charmap.h"
-#include "android/globals.h"
+#include "android/snapshot.h"
+#include "android/tcpdump.h"
#include "android/utils/bufprint.h"
#include "android/utils/debug.h"
#include "android/utils/filelock.h"
@@ -71,22 +76,17 @@
#include "android/utils/socket_drainer.h"
#include "android/utils/stralloc.h"
#include "android/utils/tempfile.h"
-#include "android/wear-agent/android_wear_agent.h"
-#include "android/display-core.h"
#include "android/utils/timezone.h"
-#include "android/snapshot.h"
-#include "android/opengles.h"
-#include "android/opengl/emugl_config.h"
-#include "android/multitouch-screen.h"
+#include "android/wear-agent/android_wear_agent.h"
#include "exec/hwaddr.h"
-#include "android/tcpdump.h"
-
-#include <unistd.h>
+#include "migration/qemu-file.h"
+#include "modem_driver.h"
+#include <errno.h>
#include <fcntl.h>
#include <signal.h>
-#include <time.h>
-#include <errno.h>
#include <sys/time.h>
+#include <time.h>
+#include <unistd.h>
#include <zlib.h>
/* Needed early for CONFIG_BSD etc. */
@@ -3127,6 +3127,18 @@ int main(int argc, char **argv, char **envp)
android_hw->disk_systemPartition_path,
android_hw->disk_systemPartition_initPath);
+ /* For ext4, to extend an internal partition to more than the default size
+ * you need to initialize userdata-qemu.img to the desired size and restore
+ * it after moving the data in - yaffs is resilient enough for this not to
+ * matter
+ */
+ if(android_op_wipe_data &&
+ userdata_partition_type == ANDROID_PARTITION_TYPE_EXT4) {
+ androidPartitionType_makeEmptyFile(userdata_partition_type,
+ android_hw->disk_dataPartition_size,
+ android_hw->disk_dataPartition_path);
+ }
+
/* Initialize data partition image */
android_nand_add_image("userdata",
userdata_partition_type,
@@ -3135,6 +3147,15 @@ int main(int argc, char **argv, char **envp)
android_hw->disk_dataPartition_path,
android_hw->disk_dataPartition_initPath);
+ /* Extend the userdata-qemu.img to the desired size - resize2fs can only
+ * extend partitions to fill available space
+ */
+ if(android_op_wipe_data &&
+ userdata_partition_type == ANDROID_PARTITION_TYPE_EXT4) {
+ resizeExt4Partition(android_hw->disk_dataPartition_path,
+ android_hw->disk_dataPartition_size);
+ }
+
/* Initialize cache partition image, if any. Its type depends on the
* kernel version. For anything >= 3.10, it must be EXT4, or
* YAFFS2 otherwise.