Refactor reading of Android properties
diff --git a/src/arm/android/api.h b/src/arm/android/api.h
index 22b2abc..17c9f19 100644
--- a/src/arm/android/api.h
+++ b/src/arm/android/api.h
@@ -25,7 +25,7 @@
 	cpuinfo_android_chipset_property_max,
 };
 
-bool cpuinfo_arm_android_parse_properties(struct cpuinfo_android_properties properties[restrict static 1]);
+void cpuinfo_arm_android_parse_properties(struct cpuinfo_android_properties properties[restrict static 1]);
 
 
 struct cpuinfo_arm_chipset cpuinfo_arm_android_decode_chipset(
diff --git a/src/arm/android/properties.c b/src/arm/android/properties.c
index a55037d..ba188a9 100644
--- a/src/arm/android/properties.c
+++ b/src/arm/android/properties.c
@@ -4,7 +4,7 @@
 #include <stddef.h>
 #include <string.h>
 
-#include <dlfcn.h>
+#include <sys/system_properties.h>
 
 #include <linux/api.h>
 #include <arm/android/api.h>
@@ -13,115 +13,7 @@
 
 #if CPUINFO_MOCK
 	#include <cpuinfo-mock.h>
-#endif
 
-
-/*
- * Size, in chars, of the on-stack buffer used for parsing lines of /system/build.prop
- * This is also the limit on the length of a single line.
- */
-#define BUFFER_SIZE 1024
-
-/*
- *	Decode a single line of /system/build.prop information.
- *	Lines have format <key>=<value>
- *	An truncated example of /system/build.prop (from Galaxy S7):
- *
- *      # ro.product.cpu.abi and ro.product.cpu.abi2 are obsolete,
- *      # use ro.product.cpu.abilist instead.
- *      ro.product.cpu.abi=arm64-v8a
- *      ro.product.cpu.abilist=arm64-v8a,armeabi-v7a,armeabi
- *      ro.product.cpu.abilist32=armeabi-v7a,armeabi
- *      ro.product.cpu.abilist64=arm64-v8a
- *      ro.product.manufacturer=samsung
- */
-static bool parse_line(
-	const char* line_start,
-	const char* line_end,
-	struct cpuinfo_android_properties properties[restrict static 1],
-	uint64_t line_number)
-{
-	/* Minimal valid line length is 3 characters: 1-character key, '=', 1-character value. */
-	const size_t line_length = line_end - line_start;
-	if (line_length < 3) {
-		return true;
-	}
-
-	/* Lines starting with '#' are comments */
-	if (line_start[0] == '#') {
-		return true;
-	}
-	
-	/* Search for '=' on the line. */
-	const char* separator = line_start;
-	for (; separator != line_end; separator++) {
-		if (*separator == '=') {
-			break;
-		}
-	}
-	/* Skip line if no '=' separator was found. */
-	if (separator == line_end) {
-		return true;
-	}
-
-	/* Skip leading spaces in value part. */
-	const char* value_start = separator + 1;
-	for (; value_start != line_end; value_start++) {
-		if (*value_start != ' ') {
-			break;
-		}
-	}
-	/* Value part contains nothing but spaces. Skip line. */
-	if (value_start == line_end) {
-		return true;
-	}
-
-	/* Skip trailing spaces in value part (if any) */
-	const char* value_end = line_end;
-	for (; value_end != value_start; value_end--) {
-		if (value_end[-1] != ' ') {
-			break;
-		}
-	}
-
-	const size_t key_length = separator - line_start;
-	const size_t value_length = value_end - value_start;
-	const size_t limited_value_length = (value_length >= CPUINFO_BUILD_PROP_VALUE_MAX) ?
-		CPUINFO_BUILD_PROP_VALUE_MAX - 1 : value_length;
-	switch (key_length) {
-		case 11:
-			if (memcmp(line_start, "ro.chipname", key_length) == 0) {
-				memcpy(properties->ro_chipname, value_start, limited_value_length);
-				cpuinfo_log_debug("parsed ro.chipname = \"%s\"",
-					properties->ro_chipname);
-			}
-			break;
-		case 16:
-			if (memcmp(line_start, "ro.product.board", key_length) == 0) {
-				memcpy(properties->ro_product_board, value_start, limited_value_length);
-				cpuinfo_log_debug("parsed ro.product.board = \"%s\"",
-					properties->ro_product_board);
-			}
-			break;
-		case 17:
-			if (memcmp(line_start, "ro.board.platform", key_length) == 0) {
-				memcpy(properties->ro_board_platform, value_start, limited_value_length);
-				cpuinfo_log_debug("parsed ro.board.platform = \"%s\"",
-					properties->ro_board_platform);
-			}
-			break;
-		case 20:
-			if (memcmp(line_start, "ro.mediatek.platform", key_length) == 0) {
-				memcpy(properties->ro_mediatek_platform, value_start, limited_value_length);
-				cpuinfo_log_debug("parsed ro.mediatek.platform = \"%s\"",
-					properties->ro_mediatek_platform);
-			}
-			break;
-	}
-	return true;
-}
-
-#if CPUINFO_MOCK
 	static struct cpuinfo_mock_property* cpuinfo_mock_properties = NULL;
 
 	void CPUINFO_ABI cpuinfo_mock_android_properties(struct cpuinfo_mock_property* properties) {
@@ -129,102 +21,39 @@
 		cpuinfo_mock_properties = properties;
 	}
 
-	static int mock_system_property_get(const char* key, char* value) {
-		for (const struct cpuinfo_mock_property* prop = cpuinfo_mock_properties; prop->key != NULL; prop++) {
-			if (strncmp(key, prop->key, CPUINFO_BUILD_PROP_NAME_MAX) == 0) {
-				strncpy(value, prop->value, CPUINFO_BUILD_PROP_VALUE_MAX);
-				return (int) strnlen(prop->value, CPUINFO_BUILD_PROP_VALUE_MAX);
+	static int cpuinfo_android_property_get(const char* key, char* value) {
+		if (cpuinfo_mock_properties != NULL) {
+			for (const struct cpuinfo_mock_property* prop = cpuinfo_mock_properties; prop->key != NULL; prop++) {
+				if (strncmp(key, prop->key, CPUINFO_BUILD_PROP_NAME_MAX) == 0) {
+					strncpy(value, prop->value, CPUINFO_BUILD_PROP_VALUE_MAX);
+					return (int) strnlen(prop->value, CPUINFO_BUILD_PROP_VALUE_MAX);
+				}
 			}
 		}
 		*value = '\0';
 		return 0;
 	}
-
-	static bool cpuinfo_arm_android_query_properties(struct cpuinfo_android_properties properties[restrict static 1]) {
-		if (cpuinfo_mock_properties == NULL) {
-			return false;
-		}
-
-		const int ro_product_board_length =
-			mock_system_property_get("ro.product.board", properties->ro_product_board);
-		cpuinfo_log_debug("read ro.product.board = \"%.*s\"",
-			ro_product_board_length, properties->ro_product_board);
-
-		const int ro_board_platform_length =
-			mock_system_property_get("ro.board.platform", properties->ro_board_platform);
-		cpuinfo_log_debug("read ro.board.platform = \"%.*s\"",
-			ro_board_platform_length, properties->ro_board_platform);
-
-		const int ro_mediatek_platform_length =
-			mock_system_property_get("ro.mediatek.platform", properties->ro_mediatek_platform);
-		cpuinfo_log_debug("read ro.mediatek.platform = \"%.*s\"",
-			ro_mediatek_platform_length, properties->ro_mediatek_platform);
-
-		const int ro_chipname_length =
-			mock_system_property_get("ro.chipname", properties->ro_chipname);
-		cpuinfo_log_debug("read ro.chipname = \"%.*s\"",
-			ro_chipname_length, properties->ro_chipname);
-
-		return true;
-	}
 #else
-	/*
-	 * Function pointer declaration for
-	 *     int __system_property_get(const char *name, char *value)
-	 * function from sys/system_properties.h header. Google's stance on whether function is part of a stable API is unclear:
-	 * it was removed from public API in some NDK versions, and then added back. In practice, libc.so has this symbol,
-	 * so we dynamically locate this function using dlopen + dlsym.
-	 */
-	typedef int (*system_property_get_ptr)(const char[], char[]);
-
-	static bool cpuinfo_arm_android_query_properties(struct cpuinfo_android_properties properties[restrict static 1]) {
-		void* libc = dlopen("libc.so", RTLD_LAZY);
-		if (libc == NULL) {
-			cpuinfo_log_warning("failed to dlopen libc.so; fallback to reading /system/build.prop for Android properties");
-			return false;
-		}
-
-		system_property_get_ptr system_property_get = (system_property_get_ptr) dlsym(libc, "__system_property_get");
-		if (system_property_get == NULL) {
-			cpuinfo_log_warning(
-				"could not find __system_property_get in libc.so: "
-				"fallback to reading /system/build.prop for Android properties");
-			goto cleanup;
-		}
-
-		const int ro_product_board_length = system_property_get("ro.product.board", properties->ro_product_board);
-		cpuinfo_log_debug("read ro.product.board = \"%.*s\"", ro_product_board_length, properties->ro_product_board);
-
-		const int ro_board_platform_length = system_property_get("ro.board.platform", properties->ro_board_platform);
-		cpuinfo_log_debug("read ro.board.platform = \"%.*s\"", ro_board_platform_length, properties->ro_board_platform);
-
-		const int ro_mediatek_platform_length =
-			system_property_get("ro.mediatek.platform", properties->ro_mediatek_platform);
-		cpuinfo_log_debug("read ro.mediatek.platform = \"%.*s\"",
-			ro_mediatek_platform_length, properties->ro_mediatek_platform);
-
-		const int ro_chipname_length = system_property_get("ro.chipname", properties->ro_chipname);
-		cpuinfo_log_debug("read ro.chipname = \"%.*s\"", ro_chipname_length, properties->ro_chipname);
-
-	cleanup:
-		dlclose(libc);
-		return system_property_get != NULL;
+	static inline int cpuinfo_android_property_get(const char* key, char* value) {
+		return __system_property_get(key, value);
 	}
 #endif
 
-bool cpuinfo_arm_android_parse_properties(struct cpuinfo_android_properties properties[restrict static 1]) {
-	memset(properties, 0, sizeof(struct cpuinfo_android_properties));
+void cpuinfo_arm_android_parse_properties(struct cpuinfo_android_properties properties[restrict static 1]) {
+	const int ro_product_board_length =
+		cpuinfo_android_property_get("ro.product.board", properties->ro_product_board);
+	cpuinfo_log_debug("read ro.product.board = \"%.*s\"", ro_product_board_length, properties->ro_product_board);
 
-	/*
-	 * First, try to use __system_property_get, which is widely supported. Whether is it a part of public API is
-	 * debatable: Android 7.0 release note suggest to use __system_property_get instead of property_get from
-	 * libcutils.so, but it was removed from headers in some NDK versions on ARM64.
-	 * If __system_property_get can't be located, fallback to parsing /system/build.prop file. This method is
-	 * recommended by  an Android engineer (see https://stackoverflow.com/a/28416743), but doesn't work on Android Oreo
-	 * (where the /system/build.prop file is not readable for non-root users) and some Huawei devices (where
-	 * /system/build.prop contains empty strings for some properties of interest).
-	 */
-	return cpuinfo_arm_android_query_properties(properties) ||
-		cpuinfo_linux_parse_multiline_file("/system/build.prop", BUFFER_SIZE,
-			(cpuinfo_line_callback) parse_line, properties);
+	const int ro_board_platform_length =
+		cpuinfo_android_property_get("ro.board.platform", properties->ro_board_platform);
+	cpuinfo_log_debug("read ro.board.platform = \"%.*s\"", ro_board_platform_length, properties->ro_board_platform);
+
+	const int ro_mediatek_platform_length =
+		cpuinfo_android_property_get("ro.mediatek.platform", properties->ro_mediatek_platform);
+	cpuinfo_log_debug("read ro.mediatek.platform = \"%.*s\"",
+		ro_mediatek_platform_length, properties->ro_mediatek_platform);
+
+	const int ro_chipname_length =
+		cpuinfo_android_property_get("ro.chipname", properties->ro_chipname);
+	cpuinfo_log_debug("read ro.chipname = \"%.*s\"", ro_chipname_length, properties->ro_chipname);
 }