Merge "Disable 64-bit Darwin platform build." into idea133
Auto-merge: 5e25267
* commit '5e2526706be97ceee436e6f0b7e6c1c35619b851':
Disable 64-bit Darwin platform build.
Add '-accel <mode>' and 'no-accel' options.
Add misc android/base/ helper classes.
Windows: Fix libSDLmain compilation
diff --git a/Makefile.android b/Makefile.android
index c5bcd0d..6d1ca2d 100644
--- a/Makefile.android
+++ b/Makefile.android
@@ -262,6 +262,13 @@
# yet due to differing procedure call ABI conventions.
EMULATOR_BUILD_64BITS := $(strip $(filter linux darwin,$(HOST_OS)))
+# Disable 64-bit build for Darwin platform builds.
+ifeq ($(HOST_OS),darwin)
+ifneq (true,$(BUILD_STANDALONE_EMULATOR))
+EMULATOR_BUILD_64BITS := $(strip $(empty))
+endif # BUILD_STANDALONE_EMULATOR != true
+endif # HOST_OS == darwin
+
include $(LOCAL_PATH)/Makefile.common
ifeq ($(HOST_OS),windows)
diff --git a/Makefile.common b/Makefile.common
index 2fa464d..ce35630 100644
--- a/Makefile.common
+++ b/Makefile.common
@@ -123,7 +123,9 @@
android/base/files/PathUtils.cpp \
android/base/Log.cpp \
android/base/String.cpp \
+ android/base/StringFormat.cpp \
android/base/StringView.cpp \
+ android/emulation/CpuAccelerator.cpp \
android/filesystems/ext4_utils.cpp \
android/kernel/kernel_utils.cpp \
android/utils/assert.c \
diff --git a/Makefile.target b/Makefile.target
index 4b9a3d9..cce444d 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -325,6 +325,7 @@
vl-android.c \
android/cmdline-option.c \
android/console.c \
+ android/cpu_accelerator.cpp \
android/display.c \
android/display-core.c \
android/help.c \
diff --git a/Makefile.tests b/Makefile.tests
index 7110433..e43996c 100644
--- a/Makefile.tests
+++ b/Makefile.tests
@@ -12,15 +12,24 @@
android/base/containers/StringVector_unittest.cpp \
android/base/EintrWrapper_unittest.cpp \
android/base/files/PathUtils_unittest.cpp \
+ android/base/files/ScopedFd_unittest.cpp \
android/base/files/ScopedStdioFile_unittest.cpp \
android/base/Log_unittest.cpp \
android/base/memory/MallocUsableSize_unittest.cpp \
android/base/memory/ScopedPtr_unittest.cpp \
android/base/String_unittest.cpp \
+ android/base/StringFormat_unittest.cpp \
android/base/StringView_unittest.cpp \
+ android/emulation/CpuAccelerator_unittest.cpp \
android/filesystems/ext4_utils_unittest.cpp \
android/kernel/kernel_utils_unittest.cpp \
+ifeq (windows,$(HOST_OS))
+EMULATOR_UNITTESTS_SOURCES += \
+ android/base/files/ScopedHandle_unittest.cpp \
+
+endif
+
$(call start-emulator-program, emulator_unittests)
LOCAL_C_INCLUDES += $(EMULATOR_GTEST_INCLUDES)
LOCAL_LDLIBS += $(EMULATOR_GTEST_LDLIBS)
diff --git a/android/base/String.h b/android/base/String.h
index fc7e41f..4e574cb 100644
--- a/android/base/String.h
+++ b/android/base/String.h
@@ -62,9 +62,13 @@
// Return current capacity.
size_t capacity() const {
- return (mStr == mStorage) ? kMinCapacity : mCapacity;
+ return (mStr == mStorage) ?
+ static_cast<size_t>(kMinCapacity) : mCapacity;
}
+ // Clear the content of a given instance.
+ void clear() { resize(0); }
+
// Array indexing operators.
char& operator[](size_t index) { return mStr[index]; }
const char& operator[](size_t index) const { return mStr[index]; }
diff --git a/android/base/StringFormat.cpp b/android/base/StringFormat.cpp
new file mode 100644
index 0000000..a3ba105
--- /dev/null
+++ b/android/base/StringFormat.cpp
@@ -0,0 +1,82 @@
+// Copyright 2014 The Android Open Source Project
+//
+// This software is licensed under the terms of the GNU General Public
+// License version 2, as published by the Free Software Foundation, and
+// may be copied, distributed, and modified under those terms.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+#include "android/base/StringFormat.h"
+
+#include <stdio.h>
+
+namespace android {
+namespace base {
+
+String StringFormat(const char* format, ...) {
+ va_list args;
+ va_start(args, format);
+ String result = StringFormatWithArgs(format, args);
+ va_end(args);
+ return result;
+}
+
+String StringFormatWithArgs(const char* format, va_list args) {
+ String result;
+ StringAppendFormatWithArgs(&result, format, args);
+ return result;
+}
+
+void StringAppendFormat(String* string, const char* format, ...) {
+ va_list args;
+ va_start(args, format);
+ StringAppendFormatWithArgs(string, format, args);
+ va_end(args);
+}
+
+void StringAppendFormatWithArgs(String* string,
+ const char* format,
+ va_list args) {
+ size_t cur_size = string->size();
+ size_t extra = 0;
+ for (;;) {
+ va_list args2;
+ va_copy(args2, args);
+ int ret = vsnprintf(&(*string)[cur_size], extra, format, args2);
+ va_end(args2);
+
+ if (ret == 0) {
+ // Nothing to do here.
+ break;
+ }
+
+ if (ret > 0) {
+ size_t ret_sz = static_cast<size_t>(ret);
+ if (extra == 0) {
+ // First pass, resize the string and try again.
+ extra = ret_sz + 1;
+ string->resize(cur_size + extra);
+ continue;
+ }
+ if (ret_sz < extra) {
+ // Second pass or later, success!
+ string->resize(cur_size + ret_sz);
+ return;
+ }
+ }
+
+ // NOTE: The MSVCRT.DLL implementation of snprintf() is broken and
+ // will return -1 in case of truncation. This code path is taken
+ // when this happens, or when |ret_sz| is equal or larger than
+ // |extra|. Grow the buffer to allow for more room, then try again.
+ extra += (extra >> 1) + 32;
+ string->resize(cur_size + extra);
+ }
+}
+
+
+} // namespace base
+} // namespace android
diff --git a/android/base/StringFormat.h b/android/base/StringFormat.h
new file mode 100644
index 0000000..c8e155d
--- /dev/null
+++ b/android/base/StringFormat.h
@@ -0,0 +1,45 @@
+// Copyright 2014 The Android Open Source Project
+//
+// This software is licensed under the terms of the GNU General Public
+// License version 2, as published by the Free Software Foundation, and
+// may be copied, distributed, and modified under those terms.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+#ifndef ANDROID_BASE_STRING_FORMAT_H
+#define ANDROID_BASE_STRING_FORMAT_H
+
+#include "android/base/String.h"
+
+#include <stdarg.h>
+
+namespace android {
+namespace base {
+
+// Create a new String instance that contains the printf-style formatted
+// output from |format| and potentially any following arguments.
+String StringFormat(const char* format, ...);
+
+// A variant of StringFormat() which uses a va_list to list formatting
+// parameters instead.
+String StringFormatWithArgs(const char* format, va_list args);
+
+// Appends a formatted string at the end of an existing string.
+// |string| is the target String instance, |format| the format string,
+// followed by any formatting parameters. This is more efficient than
+// appending the result of StringFormat(format,...) to |*string| directly.
+void StringAppendFormat(String* string, const char* format, ...);
+
+// A variant of StringAppendFormat() that takes a va_list to list
+// formatting parameters.
+void StringAppendFormatWithArgs(String* string,
+ const char* format,
+ va_list args);
+
+} // namespace base
+} // namespace android
+
+#endif // ANDROID_BASE_STRING_FORMAT_H
diff --git a/android/base/StringFormat_unittest.cpp b/android/base/StringFormat_unittest.cpp
new file mode 100644
index 0000000..7db8529
--- /dev/null
+++ b/android/base/StringFormat_unittest.cpp
@@ -0,0 +1,87 @@
+// Copyright 2014 The Android Open Source Project
+//
+// This software is licensed under the terms of the GNU General Public
+// License version 2, as published by the Free Software Foundation, and
+// may be copied, distributed, and modified under those terms.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+#include "android/base/StringFormat.h"
+
+#include <gtest/gtest.h>
+
+#include "android/base/String.h"
+
+namespace android {
+namespace base {
+
+TEST(StringFormat, EmptyString) {
+ String s = StringFormat("");
+ EXPECT_TRUE(s.empty());
+ EXPECT_STREQ("", s.c_str());
+}
+
+TEST(StringFormat, SimpleString) {
+ String s = StringFormat("foobar");
+ EXPECT_STREQ("foobar", s.c_str());
+}
+
+TEST(StringFormat, SimpleDecimal) {
+ String s = StringFormat("Pi is about %d.%d\n", 3, 1415);
+ EXPECT_STREQ("Pi is about 3.1415\n", s.c_str());
+}
+
+TEST(StringFormat, VeryLongString) {
+ static const char kPiece[] = "A hospital bed is a parked taxi with the meter running - Groucho Marx. ";
+ const size_t kPieceLen = sizeof(kPiece) - 1U;
+ String s = StringFormat("%s%s%s%s%s%s%s",
+ kPiece,
+ kPiece,
+ kPiece,
+ kPiece,
+ kPiece,
+ kPiece,
+ kPiece
+ );
+ EXPECT_EQ(7U * kPieceLen, s.size());
+ for (size_t n = 0; n < 7U; ++n) {
+ String s2 = String(s.c_str() + n * kPieceLen, kPieceLen);
+ EXPECT_STREQ(kPiece, s2.c_str()) << "Index #" << n;
+ }
+}
+
+TEST(StringAppendFormat, EmptyString) {
+ String s = "foo";
+ StringAppendFormat(&s, "");
+ EXPECT_EQ(3U, s.size());
+ EXPECT_STREQ("foo", s.c_str());
+}
+
+TEST(StringAppendFormat, SimpleString) {
+ String s = "foo";
+ StringAppendFormat(&s, "bar");
+ EXPECT_EQ(6U, s.size());
+ EXPECT_STREQ("foobar", s.c_str());
+}
+
+TEST(StringAppendFormat, VeryLongString) {
+ static const char kPiece[] = "A hospital bed is a parked taxi with the meter running - Groucho Marx. ";
+ const size_t kPieceLen = sizeof(kPiece) - 1U;
+ const size_t kCount = 12;
+ String s;
+ for (size_t n = 0; n < kCount; ++n) {
+ StringAppendFormat(&s, "%s", kPiece);
+ }
+
+ EXPECT_EQ(kCount * kPieceLen, s.size());
+ for (size_t n = 0; n < kCount; ++n) {
+ String s2 = String(s.c_str() + n * kPieceLen, kPieceLen);
+ EXPECT_STREQ(kPiece, s2.c_str()) << "Index #" << n;
+ }
+}
+
+} // namespace base
+} // namespace android
diff --git a/android/base/String_unittest.cpp b/android/base/String_unittest.cpp
index e582124..69719fb 100644
--- a/android/base/String_unittest.cpp
+++ b/android/base/String_unittest.cpp
@@ -91,6 +91,14 @@
EXPECT_EQ(kCount, s.size());
}
+TEST(String, clear) {
+ String s("foo bar");
+ EXPECT_FALSE(s.empty());
+ s.clear();
+ EXPECT_TRUE(s.empty());
+ EXPECT_EQ(0U, s.size());
+}
+
TEST(String, IndexedAccess) {
String s("foobar");
EXPECT_EQ('f', s[0]);
diff --git a/android/base/files/ScopedFd.h b/android/base/files/ScopedFd.h
new file mode 100644
index 0000000..6aa5157
--- /dev/null
+++ b/android/base/files/ScopedFd.h
@@ -0,0 +1,76 @@
+// Copyright 2014 The Android Open Source Project
+//
+// This software is licensed under the terms of the GNU General Public
+// License version 2, as published by the Free Software Foundation, and
+// may be copied, distributed, and modified under those terms.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+#ifndef ANDROID_BASE_SCOPED_FD_H
+#define ANDROID_BASE_SCOPED_FD_H
+
+#include "android/base/Compiler.h"
+
+#include <errno.h>
+#include <unistd.h>
+
+namespace android {
+namespace base {
+
+// Helper class to hold an integer file descriptor, and have the 'close'
+// function called automatically on scope exit, unless the 'release'
+// method was called previously.
+class ScopedFd {
+public:
+ // Default constructor will hold an invalid descriptor.
+ ScopedFd() : fd_(-1) {}
+
+ // Constructor takes ownership of |fd|.
+ explicit ScopedFd(int fd) : fd_(fd) {}
+
+ // Destructor calls close().
+ ~ScopedFd() { close(); }
+
+ // Return the file descriptor value, does _not_ transfer ownership.
+ int get() const { return fd_; }
+
+ // Return the file descriptor value, transfers ownership to the caller.
+ int release() {
+ int fd = fd_;
+ fd_ = -1;
+ return fd;
+ }
+
+ // Return true iff the file descriptor is valid.
+ bool valid() const { return fd_ >= 0; }
+
+ // Close the file descriptor (and make the wrapped value invalid).
+ void close() {
+ if (fd_ != -1) {
+ int save_errno = errno;
+ ::close(fd_);
+ fd_ = -1;
+ errno = save_errno;
+ }
+ }
+
+ // Swap two ScopedFd instances.
+ void swap(ScopedFd* other) {
+ int fd = fd_;
+ fd_ = other->fd_;
+ other->fd_ = fd;
+ }
+
+private:
+ DISALLOW_COPY_AND_ASSIGN(ScopedFd);
+
+ int fd_;
+};
+
+} // namespace base
+} // namespace android
+
+#endif // ANDROID_BASE_SCOPED_FD_H
diff --git a/android/base/files/ScopedFd_unittest.cpp b/android/base/files/ScopedFd_unittest.cpp
new file mode 100644
index 0000000..7ac1d69
--- /dev/null
+++ b/android/base/files/ScopedFd_unittest.cpp
@@ -0,0 +1,76 @@
+// Copyright 2014 The Android Open Source Project
+//
+// This software is licensed under the terms of the GNU General Public
+// License version 2, as published by the Free Software Foundation, and
+// may be copied, distributed, and modified under those terms.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+#include "android/base/files/ScopedFd.h"
+
+#include <unistd.h>
+#include <fcntl.h>
+
+#include <gtest/gtest.h>
+
+namespace android {
+namespace base {
+
+namespace {
+
+// The path of a file that can always be opened for reading on any platform.
+#ifdef _WIN32
+static const char kNullFile[] = "NUL";
+#else
+static const char kNullFile[] = "/dev/null";
+#endif
+
+int OpenNull() {
+ return ::open(kNullFile, O_RDONLY);
+}
+
+} // namespace
+
+TEST(ScopedFd, DefaultConstructor) {
+ ScopedFd f;
+ EXPECT_FALSE(f.valid());
+ EXPECT_EQ(-1, f.get());
+}
+
+TEST(ScopedFd, Constructor) {
+ ScopedFd f(OpenNull());
+ EXPECT_TRUE(f.valid());
+}
+
+TEST(ScopedFd, Release) {
+ ScopedFd f(OpenNull());
+ EXPECT_TRUE(f.valid());
+ int fd = f.release();
+ EXPECT_FALSE(f.valid());
+ EXPECT_NE(-1, fd);
+ ::close(fd);
+}
+
+TEST(ScopedFd, Close) {
+ ScopedFd f(OpenNull());
+ EXPECT_TRUE(f.valid());
+ f.close();
+ EXPECT_FALSE(f.valid());
+}
+
+TEST(ScopedFd, Swap) {
+ ScopedFd f1;
+ ScopedFd f2(OpenNull());
+ EXPECT_FALSE(f1.valid());
+ EXPECT_TRUE(f2.valid());
+ f1.swap(&f2);
+ EXPECT_FALSE(f2.valid());
+ EXPECT_TRUE(f1.valid());
+}
+
+
+} // namespace base
+} // namespace android
diff --git a/android/base/files/ScopedHandle.h b/android/base/files/ScopedHandle.h
new file mode 100644
index 0000000..45a97eb
--- /dev/null
+++ b/android/base/files/ScopedHandle.h
@@ -0,0 +1,78 @@
+// Copyright 2014 The Android Open Source Project
+//
+// This software is licensed under the terms of the GNU General Public
+// License version 2, as published by the Free Software Foundation, and
+// may be copied, distributed, and modified under those terms.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+#ifndef ANDROID_BASE_FILES_SCOPED_HANDLE_H
+#define ANDROID_BASE_FILES_SCOPED_HANDLE_H
+
+#if !defined(_WIN32) && !defined(_WIN64)
+#error "Only compile this file when targetting Windows!"
+#endif
+
+#include "android/base/Compiler.h"
+
+#define WIN32_LEAN_AND_MEAN 1
+#include <windows.h>
+
+namespace android {
+namespace base {
+
+// Helper class used to wrap a Win32 HANDLE that will be closed when
+// the instance is destroyed, unless the release() method was called
+// before that.
+class ScopedHandle {
+public:
+ // Default destructor is used to wrap an invalid handle value.
+ ScopedHandle() : handle_(INVALID_HANDLE_VALUE) {}
+
+ // Constructor takes ownership of |handle|.
+ explicit ScopedHandle(HANDLE handle) : handle_(handle) {}
+
+ // Destructor calls close() method.
+ ~ScopedHandle() { close(); }
+
+ // Returns true iff the wrapped HANDLE value is valid.
+ bool valid() const { return handle_ != INVALID_HANDLE_VALUE; }
+
+ // Return current HANDLE value. Does _not_ transfer ownership.
+ HANDLE get() const { return handle_; }
+
+ // Return current HANDLE value, transferring ownership to the caller.
+ HANDLE release() {
+ HANDLE h = handle_;
+ handle_ = INVALID_HANDLE_VALUE;
+ return h;
+ }
+
+ // Close handle if it is not invalid.
+ void close() {
+ if (handle_ != INVALID_HANDLE_VALUE) {
+ ::CloseHandle(handle_);
+ handle_ = INVALID_HANDLE_VALUE;
+ }
+ }
+
+ // Swap the content of two ScopedHandle instances.
+ void swap(ScopedHandle* other) {
+ HANDLE handle = handle_;
+ handle_ = other->handle_;
+ other->handle_ = handle;
+ }
+
+private:
+ DISALLOW_COPY_AND_ASSIGN(ScopedHandle);
+
+ HANDLE handle_;
+};
+
+} // namespace base
+} // namespace android
+
+#endif // ANDROID_BASE_FILES_SCOPED_HANDLE_H
diff --git a/android/base/files/ScopedHandle_unittest.cpp b/android/base/files/ScopedHandle_unittest.cpp
new file mode 100644
index 0000000..93baf9d
--- /dev/null
+++ b/android/base/files/ScopedHandle_unittest.cpp
@@ -0,0 +1,74 @@
+// Copyright 2014 The Android Open Source Project
+//
+// This software is licensed under the terms of the GNU General Public
+// License version 2, as published by the Free Software Foundation, and
+// may be copied, distributed, and modified under those terms.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+#include "android/base/files/ScopedHandle.h"
+
+#include <gtest/gtest.h>
+
+namespace android {
+namespace base {
+
+namespace {
+
+// The path of a file that can always be opened for reading on any platform.
+static const char kNullFile[] = "NUL";
+
+HANDLE OpenNull() {
+ return ::CreateFile(kNullFile,
+ GENERIC_READ,
+ FILE_SHARE_READ|FILE_SHARE_WRITE,
+ NULL,
+ OPEN_EXISTING,
+ FILE_ATTRIBUTE_NORMAL,
+ NULL);
+}
+
+} // namespace
+
+TEST(ScopedHandle, DefaultConstructor) {
+ ScopedHandle h;
+ EXPECT_FALSE(h.valid());
+ EXPECT_EQ(INVALID_HANDLE_VALUE, h.get());
+}
+
+TEST(ScopedHandle, Constructor) {
+ ScopedHandle h(OpenNull());
+ EXPECT_TRUE(h.valid());
+}
+
+TEST(ScopedHandle, Release) {
+ ScopedHandle h(OpenNull());
+ EXPECT_TRUE(h.valid());
+ HANDLE handle = h.release();
+ EXPECT_FALSE(h.valid());
+ EXPECT_NE(INVALID_HANDLE_VALUE, handle);
+ ::CloseHandle(handle);
+}
+
+TEST(ScopedHandle, Close) {
+ ScopedHandle h(OpenNull());
+ EXPECT_TRUE(h.valid());
+ h.close();
+ EXPECT_FALSE(h.valid());
+}
+
+TEST(ScopedHandle, Swap) {
+ ScopedHandle h1;
+ ScopedHandle h2(OpenNull());
+ EXPECT_FALSE(h1.valid());
+ EXPECT_TRUE(h2.valid());
+ h1.swap(&h2);
+ EXPECT_FALSE(h2.valid());
+ EXPECT_TRUE(h1.valid());
+}
+
+} // namespace base
+} // namespace android
diff --git a/android/cmdline-options.h b/android/cmdline-options.h
index 165f26e..4e02923 100644
--- a/android/cmdline-options.h
+++ b/android/cmdline-options.h
@@ -93,6 +93,9 @@
CFG_FLAG ( dynamic_skin, "dynamically construct a skin of given size, requires -skin WxH option" )
CFG_PARAM( memory, "<size>", "physical RAM size in MBs" )
+OPT_PARAM( accel, "<mode>", "Configure emulation acceleration" )
+OPT_FLAG ( no_accel, "Same as '-accel off'" )
+
OPT_PARAM( netspeed, "<speed>", "maximum network download/upload speeds" )
OPT_PARAM( netdelay, "<delay>", "network latency emulation" )
OPT_FLAG ( netfast, "disable network shaping" )
diff --git a/android/cpu_accelerator.cpp b/android/cpu_accelerator.cpp
new file mode 100644
index 0000000..872e60d
--- /dev/null
+++ b/android/cpu_accelerator.cpp
@@ -0,0 +1,32 @@
+// Copyright (C) 2014 The Android Open Source Project
+//
+// This software is licensed under the terms of the GNU General Public
+// License version 2, as published by the Free Software Foundation, and
+// may be copied, distributed, and modified under those terms.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+#include "android/cpu_accelerator.h"
+
+// This source acts as a small C++ -> C bridge between android/emulation/
+// and android/main.c
+
+#include "android/base/String.h"
+#include "android/emulation/CpuAccelerator.h"
+
+#include "android/utils/system.h"
+
+extern "C" bool android_hasCpuAcceleration(char** status_p) {
+ android::CpuAccelerator accel = android::GetCurrentCpuAccelerator();
+
+ if (status_p) {
+ android::base::String status =
+ android::GetCurrentCpuAcceleratorStatus();
+ *status_p = ASTRDUP(status.c_str());
+ }
+
+ return accel != android::CPU_ACCELERATOR_NONE;
+}
diff --git a/android/cpu_accelerator.h b/android/cpu_accelerator.h
new file mode 100644
index 0000000..845cab6
--- /dev/null
+++ b/android/cpu_accelerator.h
@@ -0,0 +1,30 @@
+// Copyright (C) 2014 The Android Open Source Project
+//
+// This software is licensed under the terms of the GNU General Public
+// License version 2, as published by the Free Software Foundation, and
+// may be copied, distributed, and modified under those terms.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+#ifndef ANDROID_CPU_ACCELERATOR_H
+#define ANDROID_CPU_ACCELERATOR_H
+
+#include <stdbool.h>
+
+#include "android/utils/compiler.h"
+
+ANDROID_BEGIN_HEADER
+
+// Returns true if CPU acceleration is possible on this machine.
+// If |status| is not NULL, on exit, |*status| will be set to a
+// heap-allocated string describing the status of acceleration,
+// to be freed by the caller.
+bool android_hasCpuAcceleration(char** status);
+
+ANDROID_END_HEADER
+
+#endif // ANDROID_CPU_ACCELERATOR_H
+
diff --git a/android/emulation/CpuAccelerator.cpp b/android/emulation/CpuAccelerator.cpp
new file mode 100644
index 0000000..be0175e
--- /dev/null
+++ b/android/emulation/CpuAccelerator.cpp
@@ -0,0 +1,347 @@
+// Copyright (C) 2014 The Android Open Source Project
+//
+// This software is licensed under the terms of the GNU General Public
+// License version 2, as published by the Free Software Foundation, and
+// may be copied, distributed, and modified under those terms.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+#include "android/emulation/CpuAccelerator.h"
+
+#ifdef _WIN32
+#define WIN32_LEAN_AND_MEAN 1
+#include <windows.h>
+#include <winioctl.h>
+#else
+#include <fcntl.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <unistd.h>
+#endif
+
+#include <stdio.h>
+
+#include "android/utils/path.h"
+
+#include "android/base/Compiler.h"
+#include "android/base/files/ScopedFd.h"
+#ifdef _WIN32
+#include "android/base/files/ScopedHandle.h"
+#endif
+#include "android/base/Log.h"
+#include "android/base/StringFormat.h"
+
+// NOTE: This source file must be independent of the rest of QEMU, as such
+// it should not include / reuse any QEMU source file or function
+// related to KVM or HAX.
+
+#ifdef __linux__
+# define HAVE_KVM 1
+# define HAVE_HAX 0
+#elif defined(_WIN32) || defined(__APPLE__)
+# define HAVE_KVM 0
+# define HAVE_HAX 1
+#else
+# error "Unsupported host platform!"
+#endif
+
+namespace android {
+
+using base::String;
+using base::StringAppendFormat;
+using base::ScopedFd;
+
+namespace {
+
+struct GlobalState {
+ bool probed;
+ bool testing;
+ CpuAccelerator accel;
+ char status[256];
+};
+
+GlobalState gGlobals = { false, false, CPU_ACCELERATOR_NONE, { '\0' } };
+
+/////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////
+/////
+///// Linux KVM support.
+/////
+/////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////
+
+#if HAVE_KVM
+
+#include <linux/kvm.h>
+
+// Return true iff KVM is installed and usable on this machine.
+// |*status| will be set to a small status string explaining the
+// status of KVM on success or failure.
+bool ProbeKVM(String *status) {
+ // 1) Check that /dev/kvm exists.
+ if (::access("/dev/kvm", F_OK)) {
+ status->assign(
+ "KVM is not installed on this machine (/dev/kvm is missing).");
+ return false;
+ }
+ // 2) Check that /dev/kvm can be opened.
+ if (::access("/dev/kvm", R_OK)) {
+ status->assign(
+ "This user doesn't have permissions to use KVM (/dev/kvm).");
+ return false;
+ }
+ // 3) Open the file.
+ ScopedFd fd(TEMP_FAILURE_RETRY(open("/dev/kvm", O_RDWR)));
+ if (!fd.valid()) {
+ status->assign("Could not open /dev/kvm :");
+ status->append(strerror(errno));
+ return false;
+ }
+
+ // 4) Extract KVM version number.
+ int version = ::ioctl(fd.get(), KVM_GET_API_VERSION, 0);
+ if (version < 0) {
+ status->assign("Could not extract KVM version: ");
+ status->append(strerror(errno));
+ return false;
+ }
+
+ // 5) Compare to minimum supported version
+ status->clear();
+
+ if (version < KVM_API_VERSION) {
+ StringAppendFormat(status,
+ "KVM version too old: %d (expected at least %d)\n",
+ version,
+ KVM_API_VERSION);
+ return false;
+ }
+
+ // 6) Profit!
+ StringAppendFormat(status,
+ "KVM (version %d) is installed and usable.",
+ version);
+ return true;
+}
+
+#endif // HAVE_KVM
+
+
+#if HAVE_HAX
+
+// Version numbers for the HAX kernel module.
+// |compat_version| is the minimum API version supported by the module.
+// |current_version| is its current API version.
+struct HaxModuleVersion {
+ uint32_t compat_version;
+ uint32_t current_version;
+};
+
+
+/////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////
+/////
+///// Windows HAX support.
+/////
+/////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////
+
+#if defined(_WIN32)
+
+using base::ScopedHandle;
+
+// Windows IOCTL code to extract HAX kernel module version.
+#define HAX_DEVICE_TYPE 0x4000
+#define HAX_IOCTL_VERSION \
+ CTL_CODE(HAX_DEVICE_TYPE, 0x900, METHOD_BUFFERED, FILE_ANY_ACCESS)
+
+// The minimum API version supported by the Android emulator.
+#define HAX_MIN_VERSION 1
+
+bool ProbeHAX(String* status) {
+ status->clear();
+ // 1) Try to find the HAX kernel module.
+ ScopedHandle hax(CreateFile("\\\\.\\HAX",
+ GENERIC_READ | GENERIC_WRITE,
+ 0,
+ NULL,
+ CREATE_ALWAYS,
+ FILE_ATTRIBUTE_NORMAL,
+ NULL));
+ if (!hax.valid()) {
+ DWORD err = GetLastError();
+ if (err == ERROR_FILE_NOT_FOUND) {
+ status->assign("HAX kernel module is not installed!");
+ } else {
+ StringAppendFormat(status,
+ "Opening HAX kernel module failed: %u",
+ err);
+ }
+ return false;
+ }
+
+ // 2) Extract the module's version.
+ HaxModuleVersion hax_version;
+
+ DWORD dSize = 0;
+ BOOL ret = DeviceIoControl(hax.get(),
+ HAX_IOCTL_VERSION,
+ NULL, 0,
+ &hax_version, sizeof(hax_version),
+ &dSize,
+ (LPOVERLAPPED) NULL);
+ if (!ret) {
+ DWORD err = GetLastError();
+ StringAppendFormat(status,
+ "Could not extract HAX module version: %u",
+ err);
+ return false;
+ }
+
+ // 3) Check that it is the right version.
+ if (hax_version.current_version < HAX_MIN_VERSION) {
+ StringAppendFormat(status,
+ "HAX version (%d) is too old (need at least %d).",
+ hax_version.current_version,
+ HAX_MIN_VERSION);
+ return false;
+ }
+
+ // 4) Profit!
+ StringAppendFormat(status,
+ "HAX (version %d) is installed and usable.",
+ hax_version.current_version);
+ return true;
+}
+
+#elif defined(__APPLE__)
+
+/////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////
+/////
+///// Darwin HAX support.
+/////
+/////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////
+
+// An IOCTL command number used to retrieve the HAX kernel module version.
+#define HAX_IOCTL_VERSION _IOWR(0, 0x20, HaxModuleVersion)
+
+// The minimum API version supported by the Android emulator.
+#define HAX_MIN_VERSION 1
+
+bool ProbeHAX(String* status) {
+ // 1) Check that /dev/HAX exists.
+ if (::access("/dev/HAX", F_OK)) {
+ status->assign(
+ "HAX is not installed on this machine (/dev/HAX is missing).");
+ return false;
+ }
+ // 2) Check that /dev/HAX can be opened.
+ if (::access("/dev/HAX", R_OK)) {
+ status->assign(
+ "This user doesn't have permission to use HAX (/dev/HAX).");
+ return false;
+ }
+ // 3) Open the file.
+ ScopedFd fd(open("/dev/HAX", O_RDWR));
+ if (!fd.valid()) {
+ status->assign("Could not open /dev/HAX: ");
+ status->append(strerror(errno));
+ return false;
+ }
+
+ // 4) Extract HAX version number.
+ status->clear();
+
+ HaxModuleVersion hax_version;
+ if (::ioctl(fd.get(), HAX_IOCTL_VERSION, &hax_version) < 0) {
+ StringAppendFormat(status,
+ "Could not extract HAX version: %s",
+ strerror(errno));
+ return false;
+ }
+
+ if (hax_version.current_version < hax_version.compat_version) {
+ StringAppendFormat(
+ status,
+ "Malformed HAX version numbers (current=%d, compat=%d)\n",
+ hax_version.current_version,
+ hax_version.compat_version);
+ return false;
+ }
+
+ // 5) Compare to minimum supported version.
+
+ if (hax_version.current_version < HAX_MIN_VERSION) {
+ StringAppendFormat(status,
+ "HAX version too old: %d (expected at least %d)\n",
+ hax_version.current_version,
+ HAX_MIN_VERSION);
+ return false;
+ }
+
+ // 6) Profit!
+ StringAppendFormat(status,
+ "HAX (version %d) is installed and usable.",
+ hax_version.current_version);
+ return true;
+}
+
+#else // !_WIN32 && !__APPLE__
+#error "Unsupported HAX host platform"
+#endif // !_WIN32 && !__APPLE__
+
+#endif // HAVE_HAX
+
+} // namespace
+
+CpuAccelerator GetCurrentCpuAccelerator() {
+ GlobalState* g = &gGlobals;
+
+ if (g->probed || g->testing) {
+ return g->accel;
+ }
+
+ String status;
+#if HAVE_KVM
+ if (ProbeKVM(&status)) {
+ g->accel = CPU_ACCELERATOR_KVM;
+ }
+#elif HAVE_HAX
+ if (ProbeHAX(&status)) {
+ g->accel = CPU_ACCELERATOR_HAX;
+ }
+#else
+ status = "This system does not support CPU acceleration.";
+#endif
+ ::snprintf(g->status, sizeof(g->status), "%s", status.c_str());
+
+ g->probed = true;
+ return g->accel;
+}
+
+String GetCurrentCpuAcceleratorStatus() {
+ GlobalState *g = &gGlobals;
+
+ if (!g->probed && !g->testing) {
+ // Force detection of the current CPU accelerator.
+ GetCurrentCpuAccelerator();
+ }
+
+ return String(g->status);
+}
+
+void SetCurrentCpuAcceleratorForTesting(CpuAccelerator accel,
+ const char* status) {
+ GlobalState *g = &gGlobals;
+
+ g->testing = true;
+ g->accel = accel;
+ ::snprintf(g->status, sizeof(g->status), "%s", status);
+}
+
+} // namespace android
diff --git a/android/emulation/CpuAccelerator.h b/android/emulation/CpuAccelerator.h
new file mode 100644
index 0000000..5c5e08e
--- /dev/null
+++ b/android/emulation/CpuAccelerator.h
@@ -0,0 +1,58 @@
+// Copyright (C) 2014 The Android Open Source Project
+//
+// This software is licensed under the terms of the GNU General Public
+// License version 2, as published by the Free Software Foundation, and
+// may be copied, distributed, and modified under those terms.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+#ifndef ANDROID_EMULATION_CPU_EMULATOR_H
+#define ANDROID_EMULATION_CPU_EMULATOR_H
+
+#include "android/base/String.h"
+
+namespace android {
+
+using ::android::base::String;
+
+// The list of CPU emulation acceleration technologies supported by the
+// Android emulator.
+// CPU_ACCELERATOR_NONE means no acceleration is supported on this machine.
+//
+// CPU_ACCELERATOR_KVM means Linux KVM, which requires a specific driver
+// to be installed and that /dev/kvm is properly accessible by the current
+// user.
+//
+// CPU_ACCELERATOR_HAX means Intel's Hardware Accelerated eXecution,
+// which can be installed on Windows and OS X machines running on an
+// Intel processor.
+//
+enum CpuAccelerator {
+ CPU_ACCELERATOR_NONE = 0,
+ CPU_ACCELERATOR_KVM,
+ CPU_ACCELERATOR_HAX,
+};
+
+// Return the CPU accelerator technology usable on the current machine.
+// This only returns CPU_ACCELERATOR_KVM or CPU_ACCELERATOR_HAX if the
+// corresponding accelerator can be used properly. Otherwise it will
+// return CPU_ACCELERATOR_NONE.
+CpuAccelerator GetCurrentCpuAccelerator();
+
+// Return an ASCII string describing the state of the current CPU
+// acceleration on this machine. If GetCurrentCpuAccelerator() returns
+// CPU_ACCELERATOR_NONE this will contain a small explanation why
+// the accelerator cannot be used.
+String GetCurrentCpuAcceleratorStatus();
+
+// For unit testing/debugging purpose only, must be called before
+// GetCurrentCpuAccelerator().
+void SetCurrentCpuAcceleratorForTesting(CpuAccelerator accel,
+ const char* status);
+
+} // namespace android
+
+#endif // ANDROID_EMULATION_CPU_EMULATOR_H
diff --git a/android/emulation/CpuAccelerator_unittest.cpp b/android/emulation/CpuAccelerator_unittest.cpp
new file mode 100644
index 0000000..68780ea
--- /dev/null
+++ b/android/emulation/CpuAccelerator_unittest.cpp
@@ -0,0 +1,62 @@
+// Copyright (C) 2014 The Android Open Source Project
+//
+// This software is licensed under the terms of the GNU General Public
+// License version 2, as published by the Free Software Foundation, and
+// may be copied, distributed, and modified under those terms.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+#include "android/emulation/CpuAccelerator.h"
+
+#include <stdio.h>
+
+#include <gtest/gtest.h>
+
+namespace android {
+
+class CpuAcceleratorTest : public ::testing::Test {
+public:
+ CpuAcceleratorTest() {
+ saved_accel_ = GetCurrentCpuAccelerator();
+ saved_status_ = GetCurrentCpuAcceleratorStatus();
+ }
+
+ ~CpuAcceleratorTest() {
+ // Restore previous state.
+ SetCurrentCpuAcceleratorForTesting(saved_accel_,
+ saved_status_.c_str());
+ }
+private:
+ CpuAccelerator saved_accel_;
+ String saved_status_;
+};
+
+// Not really a test, but a simple way to print the current accelerator
+// value for simple verification.
+TEST_F(CpuAcceleratorTest, Default) {
+ CpuAccelerator accel = GetCurrentCpuAccelerator();
+ String status = GetCurrentCpuAcceleratorStatus();
+
+ switch (accel) {
+ case CPU_ACCELERATOR_NONE:
+ printf("No acceleration possible on this machine!\n");
+ break;
+
+ case CPU_ACCELERATOR_KVM:
+ printf("KVM acceleration usable on this machine!\n");
+ break;
+
+ case CPU_ACCELERATOR_HAX:
+ printf("HAX acceleration usable on this machine!\n");
+ break;
+
+ default:
+ ASSERT_FALSE(1) << "Invalid accelerator value: " << accel;
+ }
+ printf("Status: %s\n", status.c_str());
+}
+
+} // namespace android
diff --git a/android/help.c b/android/help.c
index 17c0d89..91528b2 100644
--- a/android/help.c
+++ b/android/help.c
@@ -734,6 +734,39 @@
}
static void
+help_accel(stralloc_t *out)
+{
+ PRINTF(
+ " Use '-accel <mode>' to control how CPU emulation can be accelerated\n"
+ " when launching the Android emulator. Accelerated emulation only works\n"
+ " for x86 and x86_64 system images. On Linux, it relies on KVM being\n"
+ " installed. On Windows and OS X, it relies on an Intel CPU and the\n"
+ " Intel HAXM driver being installed on your development machine.\n"
+ " Valid values for <mode> are:\n\n"
+
+ " auto The default, determines automatically if acceleration\n"
+ " is supported, and uses it when possible.\n\n"
+
+ " off Disables acceleration entirely. Mostly useful for debugging.\n\n"
+
+ " on Force acceleration. If KVM/HAXM is not installed or usable,\n"
+ " the emulator will refuse to start and print an error message.\n\n"
+
+ " Note that this flag is ignored if you're not emulating an x86 or x86_64\n"
+ );
+}
+
+static void
+help_no_accel(stralloc_t* out)
+{
+ PRINTF(
+ " Use '-no-accel' as a shortcut to '-accel off', i.e. to disable accelerated\n"
+ " CPU emulation, when emulating an x86 or x86_64 system image. Only useful\n"
+ " for debugging.\n"
+ );
+}
+
+static void
help_skindir(stralloc_t* out)
{
PRINTF(
diff --git a/android/main.c b/android/main.c
index 62331c5..c01fa92 100644
--- a/android/main.c
+++ b/android/main.c
@@ -36,6 +36,7 @@
#include "android/utils/debug.h"
#include "android/config-file.h"
#include "android/config/config.h"
+#include "android/cpu_accelerator.h"
#include "android/kernel/kernel_utils.h"
#include "android/user-config.h"
@@ -1223,6 +1224,91 @@
args[n++] = "socket,vlan=1,mcast=230.0.0.10:1234";
}
+ /* Handle CPU acceleration options. */
+ if (opts->no_accel) {
+ if (opts->accel) {
+ if (strcmp(opts->accel, "off") != 0) {
+ derror("You cannot use -no-accel and '-accel %s' at the same time",
+ opts->accel);
+ exit(1);
+ }
+ } else {
+ AFREE(opts->accel);
+ opts->accel = ASTRDUP("off");
+ }
+ }
+
+ enum {
+ ACCEL_OFF = 0,
+ ACCEL_ON = 1,
+ ACCEL_AUTO = 2,
+ } accel_mode = ACCEL_AUTO;
+
+ if (opts->accel) {
+ if (!strcmp(opts->accel, "off")) {
+ accel_mode = ACCEL_OFF;
+ } else if (!strcmp(opts->accel, "on")) {
+ accel_mode = ACCEL_ON;
+ } else if (!strcmp(opts->accel, "auto")) {
+ accel_mode = ACCEL_AUTO;
+ } else {
+ derror("Invalid '-accel %s' parameter, valid values are: on off auto\n",
+ opts->accel);
+ exit(1);
+ }
+ }
+
+#if defined(TARGET_I386) || defined(TARGET_X86_64)
+ char* accel_status = NULL;
+ bool accel_ok = android_hasCpuAcceleration(&accel_status);
+
+#ifdef __linux__
+ static const char kEnableAccelerator[] = "-enable-kvm";
+ static const char kDisableAccelerator[] = "-disable-kvm";
+#else
+ static const char kEnableAccelerator[] = "-enable-hax";
+ static const char kDisableAccelerator[] = "-disable-hax";
+#endif
+
+ // Dump CPU acceleration status.
+ if (VERBOSE_CHECK(init)) {
+ const char* accel_str = "DISABLED";
+ if (accel_ok) {
+ if (accel_mode == ACCEL_OFF) {
+ accel_str = "working, but disabled by user";
+ } else {
+ accel_str = "working";
+ }
+ }
+ dprint("CPU Acceleration: %s", accel_str);
+ dprint("CPU Acceleration status: %s", accel_status);
+ }
+
+ // CPU acceleration only works for x86 and x86_64 system images.
+ if (accel_mode == ACCEL_OFF && accel_ok) {
+ args[n++] = ASTRDUP(kDisableAccelerator);
+ } else if (accel_mode == ACCEL_ON) {
+ if (!accel_ok) {
+ derror("CPU acceleration not supported on this machine!");
+ derror("Reason: %s", accel_status);
+ exit(1);
+ }
+ args[n++] = ASTRDUP(kEnableAccelerator);
+ } else {
+ args[n++] = accel_ok ? ASTRDUP(kEnableAccelerator)
+ : ASTRDUP(kDisableAccelerator);
+ }
+
+ AFREE(accel_status);
+#else
+ (void)accel_mode;
+
+ if (VERBOSE_CHECK(init)) {
+ dwarning("CPU acceleration only works with x86/x86_64 "
+ "system images.");
+ }
+#endif
+
/* Setup screen emulation */
if (opts->screen) {
if (strcmp(opts->screen, "touch") &&
diff --git a/distrib/sdl-1.2.15/sources.make b/distrib/sdl-1.2.15/sources.make
index 76e57f8..ea0a5e9 100644
--- a/distrib/sdl-1.2.15/sources.make
+++ b/distrib/sdl-1.2.15/sources.make
@@ -265,6 +265,7 @@
$(call start-emulator-library,emulator_libSDLmain)
LOCAL_C_INCLUDES += $(LOCAL_PATH)/include
+LOCAL_CFLAGS += $(SDL_CFLAGS)
LOCAL_SRC_FILES := $(SDLMAIN_SOURCES)
$(call end-emulator-library)
diff --git a/qemu-options.hx b/qemu-options.hx
index 48e9782..6e8495f 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -1340,12 +1340,22 @@
if KVM support is enabled when compiling.
ETEXI
+#ifdef CONFIG_HAX
+DEF("enable-hax", 0, QEMU_OPTION_enable_hax, \
+ "-enable-hax Enable HAX full virtualization support\n")
DEF("disable-hax", 0, QEMU_OPTION_disable_hax, \
"-disable-hax Disable HAX full virtualization support\n")
+#endif
+STEXI
+@item -enable-hax
+Enable HAX (Hardware-based Acceleration eXecution) support. This option is
+only supported on Max OS X and Windows platforms, if you have an Intel CPU
+which support the VT-x extension. It does not conflict with KVM.
+ETEXI
+
STEXI
@item -disable-hax
-Disable HAX (Hardware-based Acceleration eXecution) support. When HAX
-support is detected, the emulator will enable it by default. This
+Disable HAX (Hardware-based Acceleration eXecution) support. This
option will disable the default action. HAX is supported only on Mac OS X
and Windows platforms (if VT is present), and it does not conflict
with KVM.
diff --git a/vl-android.c b/vl-android.c
index 4d18b6e..cc1a4d8 100644
--- a/vl-android.c
+++ b/vl-android.c
@@ -296,7 +296,7 @@
const char *vnc_display;
int acpi_enabled = 1;
int no_hpet = 0;
-int hax_disabled = 0;
+int hax_disabled = 1;
int no_virtio_balloon = 0;
int fd_bootchk = 1;
int no_reboot = 0;
@@ -2641,9 +2641,14 @@
break;
#endif
+#ifdef CONFIG_HAX
+ case QEMU_OPTION_enable_hax:
+ hax_disabled = 0;
+ break;
case QEMU_OPTION_disable_hax:
hax_disabled = 1;
break;
+#endif
case QEMU_OPTION_android_ports:
android_op_ports = (char*)optarg;
break;