Merge "AdbdCommunicationMode: choose default from API level"
diff --git a/android/avd/util.c b/android/avd/util.c
index f7ebc35..c513d54 100644
--- a/android/avd/util.c
+++ b/android/avd/util.c
@@ -150,7 +150,6 @@
return avdPath;
}
-
char*
propertyFile_getTargetAbi(const FileData* data) {
return propertyFile_getValue((const char*)data->data,
@@ -186,57 +185,75 @@
int
-propertyFile_getApiLevel(const FileData* data) {
- char* sdkVersion = propertyFile_getValue((const char*)data->data,
- data->size,
- "ro.build.version.sdk");
- const int kMinLevel = 3;
- const int kMaxLevel = 10000;
- int level = kMinLevel;
- if (!sdkVersion) {
- D("Could not find target API sdkVersion / SDK version in build properties!");
- level = kMaxLevel;
- D("Default target API sdkVersion: %d", level);
- } else {
- char* end = NULL;
- long levelLong = strtol(sdkVersion, &end, 10);
- int level = (int)levelLong;
- if (levelLong == LONG_MIN || levelLong == LONG_MAX ||
- levelLong < 0 || !end || *end || level != levelLong) {
- level = kMinLevel;
- D("Invalid SDK version build property: '%s'", sdkVersion);
- D("Defaulting to target API sdkVersion %d", level);
- } else {
- D("Found target API sdkVersion: %d\n", level);
- }
- }
- free(sdkVersion);
- return level;
-}
-
-
-int
-propertyFile_getAdbdCommunicationMode(const FileData* data) {
+propertyFile_getInt(const FileData* data, const char* key, int _default,
+ SearchResult* searchResult) {
char* prop = propertyFile_getValue((const char*)data->data,
data->size,
- "ro.adb.qemud");
+ key);
if (!prop) {
- // No ro.adb.qemud means 'legacy' ADBD.
- return 0;
+ if (searchResult) {
+ *searchResult = RESULT_NOT_FOUND;
+ }
+ return _default;
}
char* end;
- long val = strtol(prop, &end, 10);
- if (end == NULL || *end != '\0' || val != (int)val) {
- D("Invalid ro.adb.qemud build property: '%s'", prop);
- val = 0;
- } else {
- D("Found ro.adb.qemud build property: %d", val);
+ // long is only 32 bits on windows so it isn't enough to detect int overflow
+ long long val = strtoll(prop, &end, 10);
+ if (val < INT_MIN || val > INT_MAX ||
+ end == prop || *end != '\0') {
+ D("Invalid int property: '%s:%s'", key, prop);
+ AFREE(prop);
+ if (searchResult) {
+ *searchResult = RESULT_INVALID;
+ }
+ return _default;
}
+
AFREE(prop);
+
+ if (searchResult) {
+ *searchResult = RESULT_FOUND;
+ }
return (int)val;
}
+int
+propertyFile_getApiLevel(const FileData* data) {
+ const int kMinLevel = 3;
+ const int kMaxLevel = 10000;
+ SearchResult searchResult;
+ int level = propertyFile_getInt(data, "ro.build.version.sdk", kMinLevel,
+ &searchResult);
+ if (searchResult == RESULT_NOT_FOUND) {
+ D("Could not find target API sdkVersion / SDK version in build properties!");
+ level = kMaxLevel;
+ D("Default target API sdkVersion: %d", level);
+ } else if (searchResult == RESULT_INVALID || level < 0) {
+ D("Defaulting to target API sdkVersion %d", level);
+ } else {
+ D("Found target API sdkVersion: %d\n", level);
+ }
+ return level;
+}
+
+int
+propertyFile_getAdbdCommunicationMode(const FileData* data) {
+ if ( propertyFile_getApiLevel(data) < 16 ) {
+ // QEMU pipe for ADB communication was added in android-4.1.1_r1 API 16
+ D("API < 16, forcing ro.adb.qemud==0");
+ return 0;
+ }
+
+ SearchResult searchResult;
+ int qemud = propertyFile_getInt(data, "ro.adb.qemud", 1, &searchResult);
+ if (searchResult == RESULT_FOUND) {
+ D("Found ro.adb.qemud build property: %d", qemud);
+ return qemud;
+ }
+ D("ro.adb.qemud invalid or not found, API >= 16, defaulting ro.adb.qemud==1");
+ return 1;
+}
char* path_getBuildBuildProp(const char* androidOut) {
char temp[MAX_PATH], *p = temp, *end = p + sizeof(temp);
diff --git a/android/avd/util.h b/android/avd/util.h
index 630d237..262822a 100644
--- a/android/avd/util.h
+++ b/android/avd/util.h
@@ -43,6 +43,23 @@
*/
char* path_getAvdTargetArch( const char* avdName );
+typedef enum {
+ RESULT_INVALID = -1, // key was found but value contained invalid data
+ RESULT_FOUND = 0, // key was found and value parsed correctly
+ RESULT_NOT_FOUND = 1, // key was not found (default used)
+} SearchResult;
+
+/* Retrieves an integer value associated with the key parameter
+ *
+ * |data| is a FileData instance
+ * |key| name of key to search for
+ * |searchResult| if non-null, this is set to RESULT_INVALID, RESULT_FOUND,
+ * or RESULT_NOT_FOUND
+ * Returns valid parsed int value if found, |default| otherwise
+ */
+int propertyFile_getInt(const FileData* data, const char* key, int _default,
+ SearchResult* searchResult);
+
/* Retrieves a string corresponding to the target architecture
* extracted from a build properties file.
*
diff --git a/android/avd/util_unittest.cpp b/android/avd/util_unittest.cpp
index c0aa213..0472bb2 100644
--- a/android/avd/util_unittest.cpp
+++ b/android/avd/util_unittest.cpp
@@ -10,6 +10,7 @@
// GNU General Public License for more details.
#include "android/avd/util.h"
+#include "android/utils/file_data.h"
#include <gtest/gtest.h>
@@ -27,3 +28,124 @@
EXPECT_FALSE(emulator_getBackendSuffix(NULL));
EXPECT_FALSE(emulator_getBackendSuffix("dummy"));
}
+
+TEST(AvdUtil, propertyFile_getInt) {
+ FileData fd;
+
+ const char* testFile =
+ "nineteen=19\n"
+ "int_min=-2147483648\n"
+ "int_max=2147483647\n"
+ "invalid=2147483648\n"
+ "invalid2=-2147483649\n"
+ "invalid3=bar\n"
+ "empty=\n";
+
+ EXPECT_EQ(0,fileData_initFromMemory(&fd, testFile, strlen(testFile)));
+
+ const int kDefault = 1138;
+ SearchResult kSearchResultGarbage = (SearchResult)0xdeadbeef;
+ SearchResult searchResult = kSearchResultGarbage;
+
+ EXPECT_EQ(kDefault,propertyFile_getInt(&fd, "invalid", kDefault, &searchResult));
+ EXPECT_EQ(RESULT_INVALID,searchResult);
+
+ searchResult = kSearchResultGarbage;
+ EXPECT_EQ(kDefault,propertyFile_getInt(&fd, "invalid2", kDefault, &searchResult));
+ EXPECT_EQ(RESULT_INVALID,searchResult);
+
+ searchResult = kSearchResultGarbage;
+ EXPECT_EQ(kDefault,propertyFile_getInt(&fd, "invalid3", kDefault, &searchResult));
+ EXPECT_EQ(RESULT_INVALID,searchResult);
+
+ searchResult = kSearchResultGarbage;
+ EXPECT_EQ(kDefault,propertyFile_getInt(&fd, "bar", kDefault, &searchResult));
+ EXPECT_EQ(RESULT_NOT_FOUND,searchResult);
+
+ searchResult = kSearchResultGarbage;
+ EXPECT_EQ(kDefault,propertyFile_getInt(&fd, "empty", kDefault, &searchResult));
+ EXPECT_EQ(RESULT_INVALID,searchResult);
+
+ searchResult = kSearchResultGarbage;
+ EXPECT_EQ(19,propertyFile_getInt(&fd, "nineteen", kDefault, &searchResult));
+ EXPECT_EQ(RESULT_FOUND,searchResult);
+
+ // check that null "searchResult" parameter is supported
+ EXPECT_EQ(kDefault,propertyFile_getInt(&fd, "bar", kDefault, NULL));
+ EXPECT_EQ(kDefault,propertyFile_getInt(&fd, "invalid", kDefault, NULL));
+ EXPECT_EQ(19,propertyFile_getInt(&fd, "nineteen", kDefault, NULL));
+}
+
+TEST(AvdUtil, propertyFile_getApiLevel) {
+ FileData fd;
+
+ const char* emptyFile =
+ "\n";
+
+ const char* testFile19 =
+ "ro.build.version.sdk=19\n";
+
+ const char* testFileBogus =
+ "ro.build.version.sdk=bogus\n";
+
+ EXPECT_EQ(0,fileData_initFromMemory(&fd, emptyFile, strlen(emptyFile)));
+ EXPECT_EQ(10000,propertyFile_getApiLevel(&fd));
+
+ EXPECT_EQ(0,fileData_initFromMemory(&fd, testFile19, strlen(testFile19)));
+ EXPECT_EQ(19,propertyFile_getApiLevel(&fd));
+
+ EXPECT_EQ(0,fileData_initFromMemory(&fd, testFileBogus, strlen(testFileBogus)));
+ EXPECT_EQ(3,propertyFile_getApiLevel(&fd));
+}
+
+TEST(AvdUtil, propertyFile_getAdbdCommunicationMode) {
+ FileData fd;
+
+ const char* emptyFile =
+ "\n";
+
+ const char* testFile15 =
+ "ro.build.version.sdk=15\n";
+
+ const char* testFile16 =
+ "ro.build.version.sdk=16\n";
+
+ const char* testFile15_0 =
+ "ro.build.version.sdk=15\n"
+ "ro.adb.qemud=0";
+
+ const char* testFile15_1 =
+ "ro.build.version.sdk=15\n"
+ "ro.adb.qemud=1";
+
+ const char* testFile16_0 =
+ "ro.build.version.sdk=16\n"
+ "ro.adb.qemud=0";
+
+ const char* testFile16_1 =
+ "ro.build.version.sdk=16\n"
+ "ro.adb.qemud=1";
+
+ // API unspecified -> API level == 10000
+ EXPECT_EQ(0,fileData_initFromMemory(&fd, emptyFile, strlen(emptyFile)));
+ EXPECT_EQ(1,propertyFile_getAdbdCommunicationMode(&fd));
+
+ EXPECT_EQ(0,fileData_initFromMemory(&fd, testFile15, strlen(testFile15)));
+ EXPECT_EQ(0,propertyFile_getAdbdCommunicationMode(&fd));
+
+ EXPECT_EQ(0,fileData_initFromMemory(&fd, testFile16, strlen(testFile16)));
+ EXPECT_EQ(1,propertyFile_getAdbdCommunicationMode(&fd));
+
+ EXPECT_EQ(0,fileData_initFromMemory(&fd, testFile15_0, strlen(testFile15_0)));
+ EXPECT_EQ(0,propertyFile_getAdbdCommunicationMode(&fd));
+
+ EXPECT_EQ(0,fileData_initFromMemory(&fd, testFile15_1, strlen(testFile15_1)));
+ EXPECT_EQ(0,propertyFile_getAdbdCommunicationMode(&fd));
+
+ EXPECT_EQ(0,fileData_initFromMemory(&fd, testFile16_0, strlen(testFile16_0)));
+ EXPECT_EQ(0,propertyFile_getAdbdCommunicationMode(&fd));
+
+ EXPECT_EQ(0,fileData_initFromMemory(&fd, testFile16_1, strlen(testFile16_1)));
+ EXPECT_EQ(1,propertyFile_getAdbdCommunicationMode(&fd));
+}
+