Merge changes Iede18a00,Ib0fa24fb,Ic4c8a137
* changes:
libcutils: build tests with -Wall -Wextra -Werror
libcutils: fix socket type in SocketsTest.TestGetLocalPort
libcutils: fix Wsign-compare warnings in multiuser_test
diff --git a/adb/Android.mk b/adb/Android.mk
index c51e0b8..b444afa 100644
--- a/adb/Android.mk
+++ b/adb/Android.mk
@@ -216,9 +216,9 @@
LOCAL_SRC_FILES_darwin := $(LIBADB_TEST_darwin_SRCS)
LOCAL_SRC_FILES_windows := $(LIBADB_TEST_windows_SRCS)
LOCAL_SANITIZE := $(adb_host_sanitize)
+LOCAL_SHARED_LIBRARIES := libbase
LOCAL_STATIC_LIBRARIES := \
libadb \
- libbase \
libcrypto_utils \
libcrypto \
libcutils \
@@ -232,7 +232,7 @@
LOCAL_LDFLAGS_windows := -municode
LOCAL_LDLIBS_linux := -lrt -ldl -lpthread
LOCAL_LDLIBS_darwin := -framework CoreFoundation -framework IOKit -lobjc
-LOCAL_LDLIBS_windows := -lws2_32 -luserenv -static -lwinpthread
+LOCAL_LDLIBS_windows := -lws2_32 -luserenv
LOCAL_STATIC_LIBRARIES_windows := AdbWinApi
LOCAL_MULTILIB := first
@@ -249,7 +249,7 @@
# Use wmain instead of main
LOCAL_LDFLAGS_windows := -municode
-LOCAL_LDLIBS_windows := -lws2_32 -lgdi32 -static -lwinpthread
+LOCAL_LDLIBS_windows := -lws2_32 -lgdi32
LOCAL_STATIC_LIBRARIES_windows := AdbWinApi
LOCAL_REQUIRED_MODULES_windows := AdbWinApi AdbWinUsbApi
diff --git a/adb/adb.cpp b/adb/adb.cpp
index ece143c..577e9b9 100644
--- a/adb/adb.cpp
+++ b/adb/adb.cpp
@@ -1129,6 +1129,18 @@
return 0;
}
+#if ADB_HOST
+ if (!strcmp(service, "host-features")) {
+ FeatureSet features = supported_features();
+ // Abuse features to report libusb status.
+ if (should_use_libusb()) {
+ features.insert(kFeatureLibusb);
+ }
+ SendOkay(reply_fd, FeatureSetToString(features));
+ return 0;
+ }
+#endif
+
// remove TCP transport
if (!strncmp(service, "disconnect:", 11)) {
const std::string address(service + 11);
diff --git a/adb/adb.h b/adb/adb.h
index a30e297..aea5fb8 100644
--- a/adb/adb.h
+++ b/adb/adb.h
@@ -54,7 +54,7 @@
std::string adb_version();
// Increment this when we want to force users to start a new adb server.
-#define ADB_SERVER_VERSION 38
+#define ADB_SERVER_VERSION 39
class atransport;
diff --git a/adb/client/usb_dispatch.cpp b/adb/client/usb_dispatch.cpp
index f02dccf..bfc8e16 100644
--- a/adb/client/usb_dispatch.cpp
+++ b/adb/client/usb_dispatch.cpp
@@ -17,11 +17,6 @@
#include <android-base/logging.h>
#include "usb.h"
-static bool should_use_libusb() {
- static bool enable = getenv("ADB_LIBUSB") && strcmp(getenv("ADB_LIBUSB"), "1") == 0;
- return enable;
-}
-
void usb_init() {
if (should_use_libusb()) {
LOG(DEBUG) << "using libusb backend";
diff --git a/adb/commandline.cpp b/adb/commandline.cpp
index 3b2df2e..5a2206f 100644
--- a/adb/commandline.cpp
+++ b/adb/commandline.cpp
@@ -1929,8 +1929,7 @@
else if (!strcmp(argv[0], "--version") || !strcmp(argv[0], "version")) {
fprintf(stdout, "%s", adb_version().c_str());
return 0;
- }
- else if (!strcmp(argv[0], "features")) {
+ } else if (!strcmp(argv[0], "features")) {
// Only list the features common to both the adb client and the device.
FeatureSet features;
std::string error;
@@ -1945,6 +1944,8 @@
}
}
return 0;
+ } else if (!strcmp(argv[0], "host-features")) {
+ return adb_query_command("host:host-features");
} else if (!strcmp(argv[0], "reconnect")) {
if (argc == 1) {
return adb_query_command("host:reconnect");
diff --git a/adb/set_verity_enable_state_service.cpp b/adb/set_verity_enable_state_service.cpp
index f9e028b..76b156d 100644
--- a/adb/set_verity_enable_state_service.cpp
+++ b/adb/set_verity_enable_state_service.cpp
@@ -108,11 +108,10 @@
return;
}
- std::string fstab_filename = "/fstab." + android::base::GetProperty("ro.hardware", "");
-
- fstab = fs_mgr_read_fstab(fstab_filename.c_str());
+ // read all fstab entries at once from all sources
+ fstab = fs_mgr_read_fstab_default();
if (!fstab) {
- WriteFdFmt(fd, "Failed to open %s\nMaybe run adb root?\n", fstab_filename.c_str());
+ WriteFdFmt(fd, "Failed to read fstab\nMaybe run adb root?\n");
return;
}
diff --git a/adb/transport.cpp b/adb/transport.cpp
index 60f3b5c..c951f5b 100644
--- a/adb/transport.cpp
+++ b/adb/transport.cpp
@@ -51,6 +51,7 @@
const char* const kFeatureShell2 = "shell_v2";
const char* const kFeatureCmd = "cmd";
const char* const kFeatureStat2 = "stat_v2";
+const char* const kFeatureLibusb = "libusb";
static std::string dump_packet(const char* name, const char* func, apacket* p) {
unsigned command = p->msg.command;
diff --git a/adb/transport.h b/adb/transport.h
index 3306388..490e513 100644
--- a/adb/transport.h
+++ b/adb/transport.h
@@ -47,6 +47,8 @@
// The 'cmd' command is available
extern const char* const kFeatureCmd;
extern const char* const kFeatureStat2;
+// The server is running with libusb enabled.
+extern const char* const kFeatureLibusb;
class atransport {
public:
diff --git a/adb/transport_usb.cpp b/adb/transport_usb.cpp
index 3d6cc99..e16cf12 100644
--- a/adb/transport_usb.cpp
+++ b/adb/transport_usb.cpp
@@ -97,3 +97,12 @@
{
return (usb_class == ADB_CLASS && usb_subclass == ADB_SUBCLASS && usb_protocol == ADB_PROTOCOL);
}
+
+bool should_use_libusb() {
+#if defined(_WIN32) || !ADB_HOST
+ return false;
+#else
+ static bool enable = getenv("ADB_LIBUSB") && strcmp(getenv("ADB_LIBUSB"), "1") == 0;
+ return enable;
+#endif
+}
diff --git a/adb/usb.h b/adb/usb.h
index 879bacc..ba70de4 100644
--- a/adb/usb.h
+++ b/adb/usb.h
@@ -55,3 +55,5 @@
// USB device detection.
int is_adb_interface(int usb_class, int usb_subclass, int usb_protocol);
+
+bool should_use_libusb();
diff --git a/adf/libadf/Android.bp b/adf/libadf/Android.bp
index 1a81a49..c276c53 100644
--- a/adf/libadf/Android.bp
+++ b/adf/libadf/Android.bp
@@ -14,7 +14,7 @@
cc_library_static {
name: "libadf",
- srcs: ["adf.c"],
+ srcs: ["adf.cpp"],
cflags: ["-Werror"],
local_include_dirs: ["include"],
export_include_dirs: ["include"],
diff --git a/adf/libadf/adf.c b/adf/libadf/adf.cpp
similarity index 73%
rename from adf/libadf/adf.c
rename to adf/libadf/adf.cpp
index 10f88b0..60d8ef0 100644
--- a/adf/libadf/adf.c
+++ b/adf/libadf/adf.cpp
@@ -23,6 +23,10 @@
#include <string.h>
#include <unistd.h>
+#include <algorithm>
+#include <memory>
+#include <vector>
+
#include <linux/limits.h>
#include <sys/ioctl.h>
@@ -31,52 +35,44 @@
#define ADF_BASE_PATH "/dev/"
-static ssize_t adf_find_nodes(const char *pattern, adf_id_t **ids)
+static ssize_t adf_id_vector_to_array(const std::vector<adf_id_t> &in,
+ adf_id_t **out)
{
- DIR *dir;
- struct dirent *dirent;
- size_t n = 0;
- ssize_t ret;
- adf_id_t *ids_ret = NULL;
+ auto size = sizeof(in[0]) * in.size();
+ // We can't use new[] since the existing API says the caller should free()
+ // the returned array
+ auto ret = static_cast<adf_id_t *>(malloc(size));
+ if (!ret)
+ return -ENOMEM;
- dir = opendir(ADF_BASE_PATH);
+ std::copy(in.begin(), in.end(), ret);
+ *out = ret;
+ return in.size();
+}
+
+static ssize_t adf_find_nodes(const char *pattern, adf_id_t **ids_out)
+{
+ struct dirent *dirent;
+ std::unique_ptr<DIR, decltype(&closedir)>
+ dir{opendir(ADF_BASE_PATH), closedir};
if (!dir)
return -errno;
+ std::vector<adf_id_t> ids;
errno = 0;
- while ((dirent = readdir(dir))) {
+ while ((dirent = readdir(dir.get()))) {
adf_id_t id;
int matched = sscanf(dirent->d_name, pattern, &id);
- if (matched < 0) {
- ret = -errno;
- goto done;
- } else if (matched != 1) {
- continue;
- }
-
- adf_id_t *new_ids = realloc(ids_ret, (n + 1) * sizeof(ids_ret[0]));
- if (!new_ids) {
- ret = -ENOMEM;
- goto done;
- }
-
- ids_ret = new_ids;
- ids_ret[n] = id;
- n++;
+ if (matched < 0)
+ return -errno;
+ else if (matched == 1)
+ ids.push_back(id);
}
if (errno)
- ret = -errno;
- else
- ret = n;
+ return -errno;
-done:
- closedir(dir);
- if (ret < 0)
- free(ids_ret);
- else
- *ids = ids_ret;
- return ret;
+ return adf_id_vector_to_array(ids, ids_out);
}
ssize_t adf_devices(adf_id_t **ids)
@@ -115,46 +111,29 @@
if (err < 0)
return -ENOMEM;
- if (data->n_attachments) {
- data->attachments = malloc(sizeof(data->attachments[0]) *
- data->n_attachments);
- if (!data->attachments)
- return -ENOMEM;
- }
+ if (data->n_attachments)
+ data->attachments = new adf_attachment_config[data->n_attachments];
- if (data->n_allowed_attachments) {
+ if (data->n_allowed_attachments)
data->allowed_attachments =
- malloc(sizeof(data->allowed_attachments[0]) *
- data->n_allowed_attachments);
- if (!data->allowed_attachments) {
- ret = -ENOMEM;
- goto done;
- }
- }
+ new adf_attachment_config[data->n_allowed_attachments];
- if (data->custom_data_size) {
- data->custom_data = malloc(data->custom_data_size);
- if (!data->custom_data) {
- ret = -ENOMEM;
- goto done;
- }
- }
+ if (data->custom_data_size)
+ data->custom_data = new char[data->custom_data_size];
err = ioctl(dev->fd, ADF_GET_DEVICE_DATA, data);
- if (err < 0)
+ if (err < 0) {
ret = -errno;
-
-done:
- if (ret < 0)
adf_free_device_data(data);
+ }
return ret;
}
void adf_free_device_data(struct adf_device_data *data)
{
- free(data->attachments);
- free(data->allowed_attachments);
- free(data->custom_data);
+ delete [] data->attachments;
+ delete [] data->allowed_attachments;
+ delete [] static_cast<char *>(data->custom_data);
}
int adf_device_post(struct adf_device *dev,
@@ -252,39 +231,17 @@
adf_id_t overlay_engine, adf_id_t **interfaces)
{
struct adf_device_data data;
- ssize_t n = 0;
- ssize_t ret;
- adf_id_t *ids_ret = NULL;
+ auto err = adf_get_device_data(dev, &data);
+ if (err < 0)
+ return err;
- ret = adf_get_device_data(dev, &data);
- if (ret < 0)
- return ret;
+ std::vector<adf_id_t> ids;
+ for (size_t i = 0; i < data.n_allowed_attachments; i++)
+ if (data.allowed_attachments[i].overlay_engine == overlay_engine)
+ ids.push_back(data.allowed_attachments[i].interface);
- size_t i;
- for (i = 0; i < data.n_allowed_attachments; i++) {
- if (data.allowed_attachments[i].overlay_engine != overlay_engine)
- continue;
-
- adf_id_t *new_ids = realloc(ids_ret, (n + 1) * sizeof(ids_ret[0]));
- if (!new_ids) {
- ret = -ENOMEM;
- goto done;
- }
-
- ids_ret = new_ids;
- ids_ret[n] = data.allowed_attachments[i].interface;
- n++;
- }
-
- ret = n;
-
-done:
adf_free_device_data(&data);
- if (ret < 0)
- free(ids_ret);
- else
- *interfaces = ids_ret;
- return ret;
+ return adf_id_vector_to_array(ids, interfaces);
}
static ssize_t adf_interfaces_filter(struct adf_device *dev,
@@ -292,46 +249,23 @@
bool (*filter)(struct adf_interface_data *data, __u32 match),
__u32 match)
{
- size_t n = 0;
- ssize_t ret;
- adf_id_t *ids_ret = NULL;
-
- size_t i;
- for (i = 0; i < n_in; i++) {
+ std::vector<adf_id_t> ids;
+ for (size_t i = 0; i < n_in; i++) {
int fd = adf_interface_open(dev, in[i], O_RDONLY);
- if (fd < 0) {
- ret = fd;
- goto done;
- }
+ if (fd < 0)
+ return fd;
struct adf_interface_data data;
- ret = adf_get_interface_data(fd, &data);
+ auto ret = adf_get_interface_data(fd, &data);
close(fd);
if (ret < 0)
- goto done;
+ return ret;
- if (!filter(&data, match))
- continue;
-
- adf_id_t *new_ids = realloc(ids_ret, (n + 1) * sizeof(ids_ret[0]));
- if (!new_ids) {
- ret = -ENOMEM;
- goto done;
- }
-
- ids_ret = new_ids;
- ids_ret[n] = in[i];
- n++;
+ if (filter(&data, match))
+ ids.push_back(in[i]);
}
- ret = n;
-
-done:
- if (ret < 0)
- free(ids_ret);
- else
- *out = ids_ret;
- return ret;
+ return adf_id_vector_to_array(ids, out);
}
static bool adf_interface_type_filter(struct adf_interface_data *data,
@@ -385,35 +319,24 @@
if (err < 0)
return -errno;
- if (data->n_available_modes) {
- data->available_modes = malloc(sizeof(data->available_modes[0]) *
- data->n_available_modes);
- if (!data->available_modes)
- return -ENOMEM;
- }
+ if (data->n_available_modes)
+ data->available_modes = new drm_mode_modeinfo[data->n_available_modes];
- if (data->custom_data_size) {
- data->custom_data = malloc(data->custom_data_size);
- if (!data->custom_data) {
- ret = -ENOMEM;
- goto done;
- }
- }
+ if (data->custom_data_size)
+ data->custom_data = new char[data->custom_data_size];
err = ioctl(fd, ADF_GET_INTERFACE_DATA, data);
- if (err < 0)
+ if (err < 0) {
ret = -errno;
-
-done:
- if (ret < 0)
adf_free_interface_data(data);
+ }
return ret;
}
void adf_free_interface_data(struct adf_interface_data *data)
{
- free(data->available_modes);
- free(data->custom_data);
+ delete [] data->available_modes;
+ delete [] static_cast<char *>(data->custom_data);
}
int adf_interface_blank(int fd, __u8 mode)
@@ -522,39 +445,16 @@
adf_id_t interface, adf_id_t **overlay_engines)
{
struct adf_device_data data;
- ssize_t n = 0;
- ssize_t ret;
- adf_id_t *ids_ret = NULL;
+ auto err = adf_get_device_data(dev, &data);
+ if (err < 0)
+ return err;
- ret = adf_get_device_data(dev, &data);
- if (ret < 0)
- return ret;
+ std::vector<adf_id_t> ids;
+ for (size_t i = 0; i < data.n_allowed_attachments; i++)
+ if (data.allowed_attachments[i].interface == interface)
+ ids.push_back(data.allowed_attachments[i].overlay_engine);
- size_t i;
- for (i = 0; i < data.n_allowed_attachments; i++) {
- if (data.allowed_attachments[i].interface != interface)
- continue;
-
- adf_id_t *new_ids = realloc(ids_ret, (n + 1) * sizeof(ids_ret[0]));
- if (!new_ids) {
- ret = -ENOMEM;
- goto done;
- }
-
- ids_ret = new_ids;
- ids_ret[n] = data.allowed_attachments[i].overlay_engine;
- n++;
- }
-
- ret = n;
-
-done:
- adf_free_device_data(&data);
- if (ret < 0)
- free(ids_ret);
- else
- *overlay_engines = ids_ret;
- return ret;
+ return adf_id_vector_to_array(ids, overlay_engines);
}
static ssize_t adf_overlay_engines_filter(struct adf_device *dev,
@@ -562,46 +462,24 @@
bool (*filter)(struct adf_overlay_engine_data *data, void *cookie),
void *cookie)
{
- size_t n = 0;
- ssize_t ret;
- adf_id_t *ids_ret = NULL;
-
+ std::vector<adf_id_t> ids;
size_t i;
for (i = 0; i < n_in; i++) {
int fd = adf_overlay_engine_open(dev, in[i], O_RDONLY);
- if (fd < 0) {
- ret = fd;
- goto done;
- }
+ if (fd < 0)
+ return fd;
struct adf_overlay_engine_data data;
- ret = adf_get_overlay_engine_data(fd, &data);
+ auto ret = adf_get_overlay_engine_data(fd, &data);
close(fd);
if (ret < 0)
- goto done;
+ return ret;
- if (!filter(&data, cookie))
- continue;
-
- adf_id_t *new_ids = realloc(ids_ret, (n + 1) * sizeof(ids_ret[0]));
- if (!new_ids) {
- ret = -ENOMEM;
- goto done;
- }
-
- ids_ret = new_ids;
- ids_ret[n] = in[i];
- n++;
+ if (filter(&data, cookie))
+ ids.push_back(in[i]);
}
- ret = n;
-
-done:
- if (ret < 0)
- free(ids_ret);
- else
- *out = ids_ret;
- return ret;
+ return adf_id_vector_to_array(ids, out);
}
struct format_filter_cookie {
@@ -612,7 +490,7 @@
static bool adf_overlay_engine_format_filter(
struct adf_overlay_engine_data *data, void *cookie)
{
- struct format_filter_cookie *c = cookie;
+ auto c = static_cast<format_filter_cookie *>(cookie);
size_t i;
for (i = 0; i < data->n_supported_formats; i++) {
size_t j;
@@ -656,35 +534,24 @@
if (err < 0)
return -errno;
- if (data->n_supported_formats) {
- data->supported_formats = malloc(sizeof(data->supported_formats[0]) *
- data->n_supported_formats);
- if (!data->supported_formats)
- return -ENOMEM;
- }
+ if (data->n_supported_formats)
+ data->supported_formats = new __u32[data->n_supported_formats];
- if (data->custom_data_size) {
- data->custom_data = malloc(data->custom_data_size);
- if (!data->custom_data) {
- ret = -ENOMEM;
- goto done;
- }
- }
+ if (data->custom_data_size)
+ data->custom_data = new char[data->custom_data_size];
err = ioctl(fd, ADF_GET_OVERLAY_ENGINE_DATA, data);
- if (err < 0)
+ if (err < 0) {
ret = -errno;
-
-done:
- if (ret < 0)
adf_free_overlay_engine_data(data);
+ }
return ret;
}
void adf_free_overlay_engine_data(struct adf_overlay_engine_data *data)
{
- free(data->supported_formats);
- free(data->custom_data);
+ delete [] data->supported_formats;
+ delete [] static_cast<char *>(data->custom_data);
}
bool adf_overlay_engine_supports_format(int fd, __u32 format)
@@ -724,12 +591,12 @@
int adf_read_event(int fd, struct adf_event **event)
{
struct adf_event header;
- struct {
+ struct event_with_data {
struct adf_event base;
uint8_t data[0];
- } *event_ret;
+ };
+ using unique_event = std::unique_ptr<event_with_data, decltype(&free)>;
size_t data_size;
- int ret = 0;
int err = read(fd, &header, sizeof(header));
if (err < 0)
@@ -739,28 +606,23 @@
if (header.length < sizeof(header))
return -EIO;
- event_ret = malloc(header.length);
+ // Again, we can't use new[] since the existing API says the caller should
+ // free() the returned event
+ auto event_ptr = static_cast<event_with_data *>(malloc(header.length));
+ unique_event event_ret{event_ptr, free};
if (!event_ret)
return -ENOMEM;
data_size = header.length - sizeof(header);
- memcpy(event_ret, &header, sizeof(header));
+ memcpy(event_ret.get(), &header, sizeof(header));
ssize_t read_size = read(fd, &event_ret->data, data_size);
- if (read_size < 0) {
- ret = -errno;
- goto done;
- }
- if ((size_t)read_size < data_size) {
- ret = -EIO;
- goto done;
- }
+ if (read_size < 0)
+ return -errno;
+ if ((size_t)read_size < data_size)
+ return -EIO;
- *event = &event_ret->base;
-
-done:
- if (ret < 0)
- free(event_ret);
- return ret;
+ *event = &event_ret.release()->base;
+ return 0;
}
void adf_format_str(__u32 format, char buf[ADF_FORMAT_STR_SIZE])
diff --git a/adf/libadf/tests/adf_test.cpp b/adf/libadf/tests/adf_test.cpp
index 4727c2b..82a91f4 100644
--- a/adf/libadf/tests/adf_test.cpp
+++ b/adf/libadf/tests/adf_test.cpp
@@ -188,7 +188,7 @@
const size_t AdfTest::n_fmt8888 = sizeof(fmt8888) / sizeof(fmt8888[0]);
TEST(adf, devices) {
- adf_id_t *devs;
+ adf_id_t *devs = nullptr;
ssize_t n_devs = adf_devices(&devs);
free(devs);
diff --git a/base/Android.bp b/base/Android.bp
index 694e029..7b1dc8e 100644
--- a/base/Android.bp
+++ b/base/Android.bp
@@ -78,6 +78,7 @@
host_supported: true,
clang: true,
srcs: [
+ "endian_test.cpp",
"errors_test.cpp",
"file_test.cpp",
"logging_test.cpp",
diff --git a/base/endian_test.cpp b/base/endian_test.cpp
new file mode 100644
index 0000000..963ab13
--- /dev/null
+++ b/base/endian_test.cpp
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2017 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 "android-base/endian.h"
+
+#include <gtest/gtest.h>
+
+TEST(endian, constants) {
+ ASSERT_TRUE(__LITTLE_ENDIAN == LITTLE_ENDIAN);
+ ASSERT_TRUE(__BIG_ENDIAN == BIG_ENDIAN);
+ ASSERT_TRUE(__BYTE_ORDER == BYTE_ORDER);
+
+ ASSERT_EQ(__LITTLE_ENDIAN, __BYTE_ORDER);
+}
+
+TEST(endian, smoke) {
+ static constexpr uint16_t le16 = 0x1234;
+ static constexpr uint32_t le32 = 0x12345678;
+ static constexpr uint64_t le64 = 0x123456789abcdef0;
+
+ static constexpr uint16_t be16 = 0x3412;
+ static constexpr uint32_t be32 = 0x78563412;
+ static constexpr uint64_t be64 = 0xf0debc9a78563412;
+
+ ASSERT_EQ(be16, htons(le16));
+ ASSERT_EQ(be32, htonl(le32));
+ ASSERT_EQ(be64, htonq(le64));
+
+ ASSERT_EQ(le16, ntohs(be16));
+ ASSERT_EQ(le32, ntohl(be32));
+ ASSERT_EQ(le64, ntohq(be64));
+
+ ASSERT_EQ(be16, htobe16(le16));
+ ASSERT_EQ(be32, htobe32(le32));
+ ASSERT_EQ(be64, htobe64(le64));
+
+ ASSERT_EQ(le16, betoh16(be16));
+ ASSERT_EQ(le32, betoh32(be32));
+ ASSERT_EQ(le64, betoh64(be64));
+
+ ASSERT_EQ(le16, htole16(le16));
+ ASSERT_EQ(le32, htole32(le32));
+ ASSERT_EQ(le64, htole64(le64));
+
+ ASSERT_EQ(le16, letoh16(le16));
+ ASSERT_EQ(le32, letoh32(le32));
+ ASSERT_EQ(le64, letoh64(le64));
+
+ ASSERT_EQ(le16, be16toh(be16));
+ ASSERT_EQ(le32, be32toh(be32));
+ ASSERT_EQ(le64, be64toh(be64));
+
+ ASSERT_EQ(le16, le16toh(le16));
+ ASSERT_EQ(le32, le32toh(le32));
+ ASSERT_EQ(le64, le64toh(le64));
+}
diff --git a/base/include/android-base/endian.h b/base/include/android-base/endian.h
new file mode 100644
index 0000000..6eb677c
--- /dev/null
+++ b/base/include/android-base/endian.h
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2017 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_BASE_ENDIAN_H
+#define ANDROID_BASE_ENDIAN_H
+
+/* A cross-platform equivalent of bionic's <sys/endian.h>. */
+
+#if defined(__BIONIC__)
+
+#include <sys/endian.h>
+
+#elif defined(__GLIBC__)
+
+/* glibc's <endian.h> is like bionic's <sys/endian.h>. */
+#include <endian.h>
+
+/* glibc keeps htons and htonl in <netinet/in.h>. */
+#include <netinet/in.h>
+
+/* glibc doesn't have the 64-bit variants. */
+#define htonq(x) htobe64(x)
+#define ntohq(x) be64toh(x)
+
+/* glibc has different names to BSD for these. */
+#define betoh16(x) be16toh(x)
+#define betoh32(x) be32toh(x)
+#define betoh64(x) be64toh(x)
+
+#else
+
+/* Mac OS and Windows have nothing. */
+
+#define __LITTLE_ENDIAN 1234
+#define LITTLE_ENDIAN __LITTLE_ENDIAN
+
+#define __BIG_ENDIAN 4321
+#define BIG_ENDIAN __BIG_ENDIAN
+
+#define __BYTE_ORDER __LITTLE_ENDIAN
+#define BYTE_ORDER __BYTE_ORDER
+
+#define htons(x) __builtin_bswap16(x)
+#define htonl(x) __builtin_bswap32(x)
+#define htonq(x) __builtin_bswap64(x)
+
+#define ntohs(x) __builtin_bswap16(x)
+#define ntohl(x) __builtin_bswap32(x)
+#define ntohq(x) __builtin_bswap64(x)
+
+#define htobe16(x) __builtin_bswap16(x)
+#define htobe32(x) __builtin_bswap32(x)
+#define htobe64(x) __builtin_bswap64(x)
+
+#define betoh16(x) __builtin_bswap16(x)
+#define betoh32(x) __builtin_bswap32(x)
+#define betoh64(x) __builtin_bswap64(x)
+
+#define htole16(x) (x)
+#define htole32(x) (x)
+#define htole64(x) (x)
+
+#define letoh16(x) (x)
+#define letoh32(x) (x)
+#define letoh64(x) (x)
+
+#define be16toh(x) __builtin_bswap16(x)
+#define be32toh(x) __builtin_bswap32(x)
+#define be64toh(x) __builtin_bswap64(x)
+
+#define le16toh(x) (x)
+#define le32toh(x) (x)
+#define le64toh(x) (x)
+
+#endif
+
+#endif // ANDROID_BASE_ENDIAN_H
diff --git a/base/include/android-base/logging.h b/base/include/android-base/logging.h
index 50677a3..e78edbb 100644
--- a/base/include/android-base/logging.h
+++ b/base/include/android-base/logging.h
@@ -17,6 +17,37 @@
#ifndef ANDROID_BASE_LOGGING_H
#define ANDROID_BASE_LOGGING_H
+//
+// Google-style C++ logging.
+//
+
+// This header provides a C++ stream interface to logging.
+//
+// To log:
+//
+// LOG(INFO) << "Some text; " << some_value;
+//
+// Replace `INFO` with any severity from `enum LogSeverity`.
+//
+// To log the result of a failed function and include the string
+// representation of `errno` at the end:
+//
+// PLOG(ERROR) << "Write failed";
+//
+// The output will be something like `Write failed: I/O error`.
+// Remember this as 'P' as in perror(3).
+//
+// To output your own types, simply implement operator<< as normal.
+//
+// By default, output goes to logcat on Android and stderr on the host.
+// A process can use `SetLogger` to decide where all logging goes.
+// Implementations are provided for logcat, stderr, and dmesg.
+
+// This header also provides assertions:
+//
+// CHECK(must_be_true);
+// CHECK_EQ(a, b) << z_is_interesting_too;
+
// NOTE: For Windows, you must include logging.h after windows.h to allow the
// following code to suppress the evil ERROR macro:
#ifdef _WIN32
diff --git a/fs_mgr/Android.mk b/fs_mgr/Android.mk
index 6939428..2863a26 100644
--- a/fs_mgr/Android.mk
+++ b/fs_mgr/Android.mk
@@ -25,7 +25,8 @@
fs_mgr_slotselect.cpp \
fs_mgr_verity.cpp \
fs_mgr_avb.cpp \
- fs_mgr_avb_ops.cpp
+ fs_mgr_avb_ops.cpp \
+ fs_mgr_boot_config.cpp
LOCAL_C_INCLUDES := \
$(LOCAL_PATH)/include \
system/vold \
@@ -37,6 +38,9 @@
ifneq (,$(filter userdebug,$(TARGET_BUILD_VARIANT)))
LOCAL_CFLAGS += -DALLOW_ADBD_DISABLE_VERITY=1
endif
+ifneq (,$(filter eng,$(TARGET_BUILD_VARIANT)))
+LOCAL_CFLAGS += -DALLOW_SKIP_SECURE_CHECK=1
+endif
include $(BUILD_STATIC_LIBRARY)
include $(CLEAR_VARS)
diff --git a/fs_mgr/fs_mgr.cpp b/fs_mgr/fs_mgr.cpp
index 1768078..a50817e 100644
--- a/fs_mgr/fs_mgr.cpp
+++ b/fs_mgr/fs_mgr.cpp
@@ -48,7 +48,6 @@
#include "fs_mgr_priv.h"
#include "fs_mgr_priv_avb.h"
-#include "fs_mgr_priv_verity.h"
#define KEY_LOC_PROP "ro.crypto.keyfile.userdata"
#define KEY_IN_FOOTER "footer"
@@ -436,16 +435,6 @@
return ret;
}
-static int device_is_secure() {
- int ret = -1;
- char value[PROP_VALUE_MAX];
- ret = __system_property_get("ro.secure", value);
- /* If error, we want to fail secure */
- if (ret < 0)
- return 1;
- return strcmp(value, "0") ? 1 : 0;
-}
-
static int device_is_force_encrypted() {
int ret = -1;
char value[PROP_VALUE_MAX];
@@ -661,6 +650,8 @@
}
}
+// TODO: add ueventd notifiers if they don't exist.
+// This is just doing a wait_for_device for maximum of 1s
int fs_mgr_test_access(const char *device) {
int tries = 25;
while (tries--) {
@@ -672,6 +663,23 @@
return -1;
}
+bool is_device_secure() {
+ int ret = -1;
+ char value[PROP_VALUE_MAX];
+ ret = __system_property_get("ro.secure", value);
+ if (ret == 0) {
+#ifdef ALLOW_SKIP_SECURE_CHECK
+ // Allow eng builds to skip this check if the property
+ // is not readable (happens during early mount)
+ return false;
+#else
+ // If error and not an 'eng' build, we want to fail secure.
+ return true;
+#endif
+ }
+ return strcmp(value, "0") ? true : false;
+}
+
/* When multiple fstab records share the same mount_point, it will
* try to mount each one in turn, and ignore any duplicates after a
* first successful mount.
@@ -749,7 +757,7 @@
/* Skips mounting the device. */
continue;
}
- } else if ((fstab->recs[i].fs_mgr_flags & MF_VERIFY) && device_is_secure()) {
+ } else if ((fstab->recs[i].fs_mgr_flags & MF_VERIFY) && is_device_secure()) {
int rc = fs_mgr_setup_verity(&fstab->recs[i], true);
if (__android_log_is_debuggable() && rc == FS_MGR_SETUP_VERITY_DISABLED) {
LINFO << "Verity disabled";
@@ -880,6 +888,24 @@
}
}
+/* wrapper to __mount() and expects a fully prepared fstab_rec,
+ * unlike fs_mgr_do_mount which does more things with avb / verity
+ * etc.
+ */
+int fs_mgr_do_mount_one(struct fstab_rec *rec)
+{
+ if (!rec) {
+ return FS_MGR_DOMNT_FAILED;
+ }
+
+ int ret = __mount(rec->blk_device, rec->mount_point, rec);
+ if (ret) {
+ ret = (errno == EBUSY) ? FS_MGR_DOMNT_BUSY : FS_MGR_DOMNT_FAILED;
+ }
+
+ return ret;
+}
+
/* If tmp_mount_point is non-null, mount the filesystem there. This is for the
* tmp mount we do to check the user password
* If multiple fstab entries are to be mounted on "n_name", it will try to mount each one
@@ -951,7 +977,7 @@
/* Skips mounting the device. */
continue;
}
- } else if ((fstab->recs[i].fs_mgr_flags & MF_VERIFY) && device_is_secure()) {
+ } else if ((fstab->recs[i].fs_mgr_flags & MF_VERIFY) && is_device_secure()) {
int rc = fs_mgr_setup_verity(&fstab->recs[i], true);
if (__android_log_is_debuggable() && rc == FS_MGR_SETUP_VERITY_DISABLED) {
LINFO << "Verity disabled";
@@ -1001,7 +1027,7 @@
* mount a tmpfs filesystem at the given point.
* return 0 on success, non-zero on failure.
*/
-int fs_mgr_do_tmpfs_mount(char *n_name)
+int fs_mgr_do_tmpfs_mount(const char *n_name)
{
int ret;
@@ -1171,22 +1197,3 @@
return 0;
}
-
-int fs_mgr_early_setup_verity(struct fstab_rec *fstab_rec)
-{
- if ((fstab_rec->fs_mgr_flags & MF_VERIFY) && device_is_secure()) {
- int rc = fs_mgr_setup_verity(fstab_rec, false);
- if (__android_log_is_debuggable() && rc == FS_MGR_SETUP_VERITY_DISABLED) {
- LINFO << "Verity disabled";
- return FS_MGR_EARLY_SETUP_VERITY_NO_VERITY;
- } else if (rc == FS_MGR_SETUP_VERITY_SUCCESS) {
- return FS_MGR_EARLY_SETUP_VERITY_SUCCESS;
- } else {
- return FS_MGR_EARLY_SETUP_VERITY_FAIL;
- }
- } else if (device_is_secure()) {
- LERROR << "Verity must be enabled for early mounted partitions on secured devices";
- return FS_MGR_EARLY_SETUP_VERITY_FAIL;
- }
- return FS_MGR_EARLY_SETUP_VERITY_NO_VERITY;
-}
diff --git a/fs_mgr/fs_mgr_avb.cpp b/fs_mgr/fs_mgr_avb.cpp
index 68efb00..2cb7e34 100644
--- a/fs_mgr/fs_mgr_avb.cpp
+++ b/fs_mgr/fs_mgr_avb.cpp
@@ -441,18 +441,23 @@
static bool init_is_avb_used() {
// When AVB is used, boot loader should set androidboot.vbmeta.{hash_alg,
- // size, digest} in kernel cmdline. They will then be imported by init
- // process to system properties: ro.boot.vbmeta.{hash_alg, size, digest}.
+ // size, digest} in kernel cmdline or in device tree. They will then be
+ // imported by init process to system properties: ro.boot.vbmeta.{hash_alg, size, digest}.
+ //
+ // In case of early mount, init properties are not initialized, so we also
+ // ensure we look into kernel command line and device tree if the property is
+ // not found
//
// Checks hash_alg as an indicator for whether AVB is used.
// We don't have to parse and check all of them here. The check will
// be done in fs_mgr_load_vbmeta_images() and FS_MGR_SETUP_AVB_FAIL will
// be returned when there is an error.
- std::string hash_alg = android::base::GetProperty("ro.boot.vbmeta.hash_alg", "");
-
- if (hash_alg == "sha256" || hash_alg == "sha512") {
- return true;
+ std::string hash_alg;
+ if (fs_mgr_get_boot_config("vbmeta.hash_alg", &hash_alg) == 0) {
+ if (hash_alg == "sha256" || hash_alg == "sha512") {
+ return true;
+ }
}
return false;
@@ -482,10 +487,11 @@
// Sets requested_partitions to nullptr as it's to copy the contents
// of HASH partitions into fs_mgr_avb_verify_data, which is not required as
// fs_mgr only deals with HASHTREE partitions.
- const char* requested_partitions[] = {nullptr};
- const char* ab_suffix = android::base::GetProperty("ro.boot.slot_suffix", "").c_str();
+ const char *requested_partitions[] = {nullptr};
+ std::string ab_suffix;
+ fs_mgr_get_boot_config("slot_suffix", &ab_suffix);
AvbSlotVerifyResult verify_result =
- avb_slot_verify(fs_mgr_avb_ops, requested_partitions, ab_suffix,
+ avb_slot_verify(fs_mgr_avb_ops, requested_partitions, ab_suffix.c_str(),
fs_mgr_vbmeta_prop.allow_verification_error, &fs_mgr_avb_verify_data);
// Only allow two verify results:
diff --git a/fs_mgr/fs_mgr_boot_config.cpp b/fs_mgr/fs_mgr_boot_config.cpp
new file mode 100644
index 0000000..5b2f218
--- /dev/null
+++ b/fs_mgr/fs_mgr_boot_config.cpp
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2017 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 <android-base/file.h>
+#include <android-base/stringprintf.h>
+#include <android-base/strings.h>
+#include <android-base/properties.h>
+
+#include "fs_mgr_priv.h"
+
+// Tries to get the boot config value in properties, kernel cmdline and
+// device tree (in that order). returns 'true' if successfully found, 'false'
+// otherwise
+bool fs_mgr_get_boot_config(const std::string& key, std::string* out_val) {
+ FS_MGR_CHECK(out_val != nullptr);
+
+ // first check if we have "ro.boot" property already
+ *out_val = android::base::GetProperty("ro.boot." + key, "");
+ if (!out_val->empty()) {
+ return true;
+ }
+
+ // fallback to kernel cmdline, properties may not be ready yet
+ std::string cmdline;
+ std::string cmdline_key("androidboot." + key);
+ if (android::base::ReadFileToString("/proc/cmdline", &cmdline)) {
+ for (const auto& entry : android::base::Split(android::base::Trim(cmdline), " ")) {
+ std::vector<std::string> pieces = android::base::Split(entry, "=");
+ if (pieces.size() == 2) {
+ if (pieces[0] == cmdline_key) {
+ *out_val = pieces[1];
+ return true;
+ }
+ }
+ }
+ }
+
+ // lastly, check the device tree
+ if (is_dt_compatible()) {
+ std::string file_name = kAndroidDtDir + "/" + key;
+ // DT entries terminate with '\0' but so do the properties
+ if (android::base::ReadFileToString(file_name, out_val)) {
+ return true;
+ }
+
+ LERROR << "Error finding '" << key << "' in device tree";
+ }
+
+ return false;
+}
diff --git a/fs_mgr/fs_mgr_fstab.cpp b/fs_mgr/fs_mgr_fstab.cpp
index 48ddf29..5b0243d 100644
--- a/fs_mgr/fs_mgr_fstab.cpp
+++ b/fs_mgr/fs_mgr_fstab.cpp
@@ -15,6 +15,7 @@
*/
#include <ctype.h>
+#include <dirent.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
@@ -22,6 +23,10 @@
#include <sys/mount.h>
#include <unistd.h>
+#include <android-base/file.h>
+#include <android-base/stringprintf.h>
+#include <android-base/strings.h>
+
#include "fs_mgr_priv.h"
struct fs_mgr_flag_values {
@@ -130,6 +135,24 @@
return size;
}
+/* fills 'dt_value' with the underlying device tree value string without
+ * the trailing '\0'. Returns true if 'dt_value' has a valid string, 'false'
+ * otherwise.
+ */
+static bool read_dt_file(const std::string& file_name, std::string* dt_value)
+{
+ if (android::base::ReadFileToString(file_name, dt_value)) {
+ if (!dt_value->empty()) {
+ // trim the trailing '\0' out, otherwise the comparison
+ // will produce false-negatives.
+ dt_value->resize(dt_value->size() - 1);
+ return true;
+ }
+ }
+
+ return false;
+}
+
static int parse_flags(char *flags, struct flag_list *fl,
struct fs_mgr_flag_values *flag_vals,
char *fs_options, int fs_options_len)
@@ -290,6 +313,97 @@
return f;
}
+static bool is_dt_fstab_compatible() {
+ std::string dt_value;
+ std::string file_name = kAndroidDtDir + "/fstab/compatible";
+ if (read_dt_file(file_name, &dt_value)) {
+ if (dt_value == "android,fstab") {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+static std::string read_fstab_from_dt() {
+ std::string fstab;
+ if (!is_dt_compatible() || !is_dt_fstab_compatible()) {
+ return fstab;
+ }
+
+ std::string fstabdir_name = kAndroidDtDir + "/fstab";
+ std::unique_ptr<DIR, int (*)(DIR*)> fstabdir(opendir(fstabdir_name.c_str()), closedir);
+ if (!fstabdir) return fstab;
+
+ dirent* dp;
+ while ((dp = readdir(fstabdir.get())) != NULL) {
+ // skip over name and compatible
+ if (dp->d_type != DT_DIR) {
+ continue;
+ }
+
+ // skip if its not 'vendor', 'odm' or 'system'
+ if (strcmp(dp->d_name, "odm") && strcmp(dp->d_name, "system") &&
+ strcmp(dp->d_name, "vendor")) {
+ continue;
+ }
+
+ // create <dev> <mnt_point> <type> <mnt_flags> <fsmgr_flags>\n
+ std::vector<std::string> fstab_entry;
+ std::string file_name;
+ std::string value;
+ file_name = android::base::StringPrintf("%s/%s/dev", fstabdir_name.c_str(), dp->d_name);
+ if (!read_dt_file(file_name, &value)) {
+ LERROR << "dt_fstab: Failed to find device for partition " << dp->d_name;
+ fstab.clear();
+ break;
+ }
+ fstab_entry.push_back(value);
+ fstab_entry.push_back(android::base::StringPrintf("/%s", dp->d_name));
+
+ file_name = android::base::StringPrintf("%s/%s/type", fstabdir_name.c_str(), dp->d_name);
+ if (!read_dt_file(file_name, &value)) {
+ LERROR << "dt_fstab: Failed to find type for partition " << dp->d_name;
+ fstab.clear();
+ break;
+ }
+ fstab_entry.push_back(value);
+
+ file_name = android::base::StringPrintf("%s/%s/mnt_flags", fstabdir_name.c_str(), dp->d_name);
+ if (!read_dt_file(file_name, &value)) {
+ LERROR << "dt_fstab: Failed to find type for partition " << dp->d_name;
+ fstab.clear();
+ break;
+ }
+ fstab_entry.push_back(value);
+
+ file_name = android::base::StringPrintf("%s/%s/fsmgr_flags", fstabdir_name.c_str(), dp->d_name);
+ if (!read_dt_file(file_name, &value)) {
+ LERROR << "dt_fstab: Failed to find type for partition " << dp->d_name;
+ fstab.clear();
+ break;
+ }
+ fstab_entry.push_back(value);
+
+ fstab += android::base::Join(fstab_entry, " ");
+ fstab += '\n';
+ }
+
+ return fstab;
+}
+
+bool is_dt_compatible() {
+ std::string file_name = kAndroidDtDir + "/compatible";
+ std::string dt_value;
+ if (read_dt_file(file_name, &dt_value)) {
+ if (dt_value == "android,firmware") {
+ return true;
+ }
+ }
+
+ return false;
+}
+
struct fstab *fs_mgr_read_fstab_file(FILE *fstab_file)
{
int cnt, entries;
@@ -444,6 +558,84 @@
return fstab;
}
+/* Returns fstab entries parsed from the device tree if they
+ * exist
+ */
+struct fstab *fs_mgr_read_fstab_dt()
+{
+ std::string fstab_buf = read_fstab_from_dt();
+ if (fstab_buf.empty()) {
+ return NULL;
+ }
+
+ std::unique_ptr<FILE, decltype(&fclose)> fstab_file(
+ fmemopen(static_cast<void*>(const_cast<char*>(fstab_buf.c_str())),
+ fstab_buf.length(), "r"), fclose);
+ if (!fstab_file) {
+ return NULL;
+ }
+
+ struct fstab *fstab = fs_mgr_read_fstab_file(fstab_file.get());
+ if (!fstab) {
+ LERROR << "failed to load fstab from kernel:" << std::endl << fstab_buf;
+ }
+
+ return fstab;
+}
+
+/* combines fstab entries passed in from device tree with
+ * the ones found in /fstab.<hardware>
+ */
+struct fstab *fs_mgr_read_fstab_default()
+{
+ struct fstab *fstab = fs_mgr_read_fstab_dt();
+ std::string hw;
+ if (!fs_mgr_get_boot_config("hardware", &hw)) {
+ // if we fail to find this, return whatever was found in device tree
+ LWARNING << "failed to find device hardware name";
+ return fstab;
+ }
+
+ std::string default_fstab = FSTAB_PREFIX + hw;
+ struct fstab *f = fs_mgr_read_fstab(default_fstab.c_str());
+ if (!f) {
+ // return what we have
+ LWARNING << "failed to read fstab entries from '" << default_fstab << "'";
+ return fstab;
+ }
+
+ // return the fstab read from file if device tree doesn't
+ // have one, other wise merge the two
+ if (!fstab) {
+ fstab = f;
+ } else {
+ int total_entries = fstab->num_entries + f->num_entries;
+ fstab->recs = static_cast<struct fstab_rec *>(realloc(
+ fstab->recs, total_entries * (sizeof(struct fstab_rec))));
+ if (!fstab->recs) {
+ LERROR << "failed to allocate fstab recs";
+ fstab->num_entries = 0;
+ fs_mgr_free_fstab(fstab);
+ return NULL;
+ }
+
+ for (int i = fstab->num_entries, j = 0; i < total_entries; i++, j++) {
+ // copy everything and *not* strdup
+ fstab->recs[i] = f->recs[j];
+ }
+
+ // free up fstab entries read from file, but don't cleanup
+ // the strings within f->recs[X] to make sure they are accessible
+ // through fstab->recs[X].
+ free(f->fstab_filename);
+ free(f);
+
+ fstab->num_entries = total_entries;
+ }
+
+ return fstab;
+}
+
void fs_mgr_free_fstab(struct fstab *fstab)
{
int i;
@@ -557,6 +749,11 @@
return fstab->fs_mgr_flags & MF_VERIFY;
}
+int fs_mgr_is_verifyatboot(const struct fstab_rec *fstab)
+{
+ return fstab->fs_mgr_flags & MF_VERIFYATBOOT;
+}
+
int fs_mgr_is_encryptable(const struct fstab_rec *fstab)
{
return fstab->fs_mgr_flags & (MF_CRYPT | MF_FORCECRYPT | MF_FORCEFDEORFBE);
diff --git a/fs_mgr/fs_mgr_priv.h b/fs_mgr/fs_mgr_priv.h
index 79c27c4..4e2ac8b 100644
--- a/fs_mgr/fs_mgr_priv.h
+++ b/fs_mgr/fs_mgr_priv.h
@@ -19,6 +19,7 @@
#include <android-base/logging.h>
#include <fs_mgr.h>
+#include "fs_mgr_priv_boot_config.h"
/* The CHECK() in logging.h will use program invocation name as the tag.
* Thus, the log will have prefix "init: " when libfs_mgr is statically
@@ -40,6 +41,8 @@
#define PWARNING PLOG(WARNING) << FS_MGR_TAG
#define PERROR PLOG(ERROR) << FS_MGR_TAG
+const std::string FSTAB_PREFIX("/fstab.");
+
__BEGIN_DECLS
#define CRYPTO_TMPFS_OPTIONS "size=256m,mode=0771,uid=1000,gid=1000"
@@ -114,6 +117,8 @@
int fs_mgr_set_blk_ro(const char *blockdev);
int fs_mgr_test_access(const char *device);
int fs_mgr_update_for_slotselect(struct fstab *fstab);
+bool is_dt_compatible();
+bool is_device_secure();
__END_DECLS
diff --git a/fs_mgr/fs_mgr_priv_verity.h b/fs_mgr/fs_mgr_priv_boot_config.h
similarity index 63%
rename from fs_mgr/fs_mgr_priv_verity.h
rename to fs_mgr/fs_mgr_priv_boot_config.h
index 1a6d215..8773d33 100644
--- a/fs_mgr/fs_mgr_priv_verity.h
+++ b/fs_mgr/fs_mgr_priv_boot_config.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2013 The Android Open Source Project
+ * Copyright (C) 2017 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.
@@ -14,14 +14,14 @@
* limitations under the License.
*/
+#ifndef __CORE_FS_MGR_PRIV_BOOTCONFIG_H
+#define __CORE_FS_MGR_PRIV_BOOTCONFIG_H
+
#include <sys/cdefs.h>
+#include <string>
-#define FS_MGR_SETUP_VERITY_DISABLED (-2)
-#define FS_MGR_SETUP_VERITY_FAIL (-1)
-#define FS_MGR_SETUP_VERITY_SUCCESS 0
+const std::string kAndroidDtDir("/proc/device-tree/firmware/android");
-__BEGIN_DECLS
+bool fs_mgr_get_boot_config(const std::string& key, std::string* out_val);
-int fs_mgr_setup_verity(struct fstab_rec *fstab, bool verify_dev);
-
-__END_DECLS
+#endif /* __CORE_FS_MGR_PRIV_BOOTCONFIG_H */
diff --git a/fs_mgr/fs_mgr_slotselect.cpp b/fs_mgr/fs_mgr_slotselect.cpp
index b30417f..f3bba7b 100644
--- a/fs_mgr/fs_mgr_slotselect.cpp
+++ b/fs_mgr/fs_mgr_slotselect.cpp
@@ -14,118 +14,31 @@
* limitations under the License.
*/
-#include <fcntl.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <unistd.h>
-
-#include <ctype.h>
-#include <errno.h>
#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include <android-base/file.h>
-#include <android-base/stringprintf.h>
-#include <android-base/strings.h>
-#include <cutils/properties.h>
#include "fs_mgr.h"
#include "fs_mgr_priv.h"
-// finds slot_suffix in androidboot.slot_suffix kernel command line argument
-// or in the device tree node at /firmware/android/slot_suffix property
-static int get_active_slot_suffix_from_kernel(char *out_suffix,
- size_t suffix_len)
-{
- std::string cmdline;
- if (android::base::ReadFileToString("/proc/cmdline", &cmdline)) {
- for (const auto& entry : android::base::Split(android::base::Trim(cmdline), " ")) {
- std::vector<std::string> pieces = android::base::Split(entry, "=");
- if (pieces.size() == 2) {
- if (pieces[0] == "androidboot.slot_suffix") {
- strncpy(out_suffix, pieces[1].c_str(), suffix_len);
- return 0;
- }
- }
- }
- }
-
- // if we can't find slot_suffix in cmdline, check the DT
- static constexpr char android_dt_dir[] = "/proc/device-tree/firmware/android";
- std::string file_name = android::base::StringPrintf("%s/compatible", android_dt_dir);
- std::string dt_value;
- if (android::base::ReadFileToString(file_name, &dt_value)) {
- if (!dt_value.compare("android,firmware")) {
- LERROR << "Error finding compatible android DT node";
- return -1;
- }
-
- file_name = android::base::StringPrintf("%s/%s", android_dt_dir, "slot_suffix");
- if (!android::base::ReadFileToString(file_name, &dt_value)) {
- LERROR << "Error finding slot_suffix in device tree";
- return -1;
- }
-
- // DT entries have a terminating '\0', so 'suffix_len' is safe.
- strncpy(out_suffix, dt_value.c_str(), suffix_len);
- return 0;
- }
-
- // slot_suffix missing in kernel cmdline or device tree
- return -1;
-}
-
-// Gets slot_suffix from either the kernel cmdline / device tree. Sets
-// |out_suffix| on success and returns 0. Returns -1 if slot_suffix could not
-// be determined.
-static int get_active_slot_suffix(char *out_suffix, size_t suffix_len)
-{
- char propbuf[PROPERTY_VALUE_MAX];
-
- // Get the suffix from the kernel commandline (note that we don't
- // allow the empty suffix). On bootloaders natively supporting A/B
- // we'll hit this path every time so don't bother logging it.
- property_get("ro.boot.slot_suffix", propbuf, "");
- if (propbuf[0] != '\0') {
- strncpy(out_suffix, propbuf, suffix_len);
- return 0;
- }
-
- // if the property is not set, we are probably being invoked early during
- // boot. Try to find the slotsuffix ourselves in the kernel command line
- // or the device tree
- if (get_active_slot_suffix_from_kernel(out_suffix, suffix_len) == 0) {
- LINFO << "Using slot suffix '" << out_suffix << "' from kernel";
- return 0;
- }
-
- LERROR << "Error determining slot_suffix";
-
- return -1;
-}
-
// Updates |fstab| for slot_suffix. Returns 0 on success, -1 on error.
int fs_mgr_update_for_slotselect(struct fstab *fstab)
{
int n;
- char suffix[PROPERTY_VALUE_MAX];
int got_suffix = 0;
+ std::string suffix;
for (n = 0; n < fstab->num_entries; n++) {
if (fstab->recs[n].fs_mgr_flags & MF_SLOTSELECT) {
char *tmp;
if (!got_suffix) {
- memset(suffix, '\0', sizeof(suffix));
- if (get_active_slot_suffix(suffix, sizeof(suffix) - 1) != 0) {
+ if (!fs_mgr_get_boot_config("slot_suffix", &suffix)) {
return -1;
}
got_suffix = 1;
}
if (asprintf(&tmp, "%s%s", fstab->recs[n].blk_device,
- suffix) > 0) {
+ suffix.c_str()) > 0) {
free(fstab->recs[n].blk_device);
fstab->recs[n].blk_device = tmp;
} else {
diff --git a/fs_mgr/fs_mgr_verity.cpp b/fs_mgr/fs_mgr_verity.cpp
index 1ec4540..e8ed6a2 100644
--- a/fs_mgr/fs_mgr_verity.cpp
+++ b/fs_mgr/fs_mgr_verity.cpp
@@ -45,9 +45,6 @@
#include "fs_mgr.h"
#include "fs_mgr_priv.h"
#include "fs_mgr_priv_dm_ioctl.h"
-#include "fs_mgr_priv_verity.h"
-
-#define FSTAB_PREFIX "/fstab."
#define VERITY_TABLE_RSA_KEY "/verity_key"
#define VERITY_TABLE_HASH_IDX 8
@@ -658,7 +655,6 @@
static int load_verity_state(struct fstab_rec *fstab, int *mode)
{
- char propbuf[PROPERTY_VALUE_MAX];
int match = 0;
off64_t offset = 0;
@@ -666,10 +662,9 @@
*mode = VERITY_MODE_EIO;
/* use the kernel parameter if set */
- property_get("ro.boot.veritymode", propbuf, "");
-
- if (*propbuf != '\0') {
- if (!strcmp(propbuf, "enforcing")) {
+ std::string veritymode;
+ if (fs_mgr_get_boot_config("veritymode", &veritymode)) {
+ if (veritymode.compare("enforcing")) {
*mode = VERITY_MODE_DEFAULT;
}
return 0;
@@ -697,8 +692,6 @@
int fs_mgr_load_verity_state(int *mode)
{
- char fstab_filename[PROPERTY_VALUE_MAX + sizeof(FSTAB_PREFIX)];
- char propbuf[PROPERTY_VALUE_MAX];
int rc = -1;
int i;
int current;
@@ -708,13 +701,9 @@
* logging mode, in which case return that */
*mode = VERITY_MODE_DEFAULT;
- property_get("ro.hardware", propbuf, "");
- snprintf(fstab_filename, sizeof(fstab_filename), FSTAB_PREFIX"%s", propbuf);
-
- fstab = fs_mgr_read_fstab(fstab_filename);
-
+ fstab = fs_mgr_read_fstab_default();
if (!fstab) {
- LERROR << "Failed to read " << fstab_filename;
+ LERROR << "Failed to read default fstab";
goto out;
}
@@ -748,7 +737,6 @@
{
alignas(dm_ioctl) char buffer[DM_BUF_SIZE];
bool system_root = false;
- char fstab_filename[PROPERTY_VALUE_MAX + sizeof(FSTAB_PREFIX)];
std::string mount_point;
char propbuf[PROPERTY_VALUE_MAX];
const char *status;
@@ -768,22 +756,16 @@
}
fd = TEMP_FAILURE_RETRY(open("/dev/device-mapper", O_RDWR | O_CLOEXEC));
-
if (fd == -1) {
PERROR << "Error opening device mapper";
goto out;
}
- property_get("ro.hardware", propbuf, "");
- snprintf(fstab_filename, sizeof(fstab_filename), FSTAB_PREFIX"%s", propbuf);
-
property_get("ro.build.system_root_image", propbuf, "");
system_root = !strcmp(propbuf, "true");
-
- fstab = fs_mgr_read_fstab(fstab_filename);
-
+ fstab = fs_mgr_read_fstab_default();
if (!fstab) {
- LERROR << "Failed to read " << fstab_filename;
+ LERROR << "Failed to read default fstab";
goto out;
}
@@ -859,7 +841,10 @@
*table = strdup(result.c_str());
}
-int fs_mgr_setup_verity(struct fstab_rec *fstab, bool verify_dev)
+// prepares the verity enabled (MF_VERIFY / MF_VERIFYATBOOT) fstab record for
+// mount. The 'wait_for_verity_dev' parameter makes this function wait for the
+// verity device to get created before return
+int fs_mgr_setup_verity(struct fstab_rec *fstab, bool wait_for_verity_dev)
{
int retval = FS_MGR_SETUP_VERITY_FAIL;
int fd = -1;
@@ -873,6 +858,13 @@
const std::string mount_point(basename(fstab->mount_point));
bool verified_at_boot = false;
+ // This is a public API and so deserves its own check to see if verity
+ // setup is needed at all.
+ if (!is_device_secure()) {
+ LINFO << "Verity setup skipped for " << mount_point;
+ return FS_MGR_SETUP_VERITY_SUCCESS;
+ }
+
if (fec_open(&f, fstab->blk_device, O_RDONLY, FEC_VERITY_DISABLE,
FEC_DEFAULT_ROOTS) < 0) {
PERROR << "Failed to open '" << fstab->blk_device << "'";
@@ -1026,7 +1018,7 @@
}
// make sure we've set everything up properly
- if (verify_dev && fs_mgr_test_access(fstab->blk_device) < 0) {
+ if (wait_for_verity_dev && fs_mgr_test_access(fstab->blk_device) < 0) {
goto out;
}
diff --git a/fs_mgr/include/fs_mgr.h b/fs_mgr/include/fs_mgr.h
index a9deed9..a5e5beb 100644
--- a/fs_mgr/include/fs_mgr.h
+++ b/fs_mgr/include/fs_mgr.h
@@ -85,6 +85,8 @@
typedef void (*fs_mgr_verity_state_callback)(struct fstab_rec *fstab,
const char *mount_point, int mode, int status);
+struct fstab *fs_mgr_read_fstab_default();
+struct fstab *fs_mgr_read_fstab_dt();
struct fstab *fs_mgr_read_fstab_file(FILE *fstab_file);
struct fstab *fs_mgr_read_fstab(const char *fstab_path);
void fs_mgr_free_fstab(struct fstab *fstab);
@@ -103,7 +105,8 @@
int fs_mgr_do_mount(struct fstab *fstab, const char *n_name, char *n_blk_device,
char *tmp_mount_point);
-int fs_mgr_do_tmpfs_mount(char *n_name);
+int fs_mgr_do_mount_one(struct fstab_rec *rec);
+int fs_mgr_do_tmpfs_mount(const char *n_name);
int fs_mgr_unmount_all(struct fstab *fstab);
int fs_mgr_get_crypt_info(struct fstab *fstab, char *key_loc,
char *real_blk_device, int size);
@@ -116,6 +119,7 @@
int fs_mgr_is_voldmanaged(const struct fstab_rec *fstab);
int fs_mgr_is_nonremovable(const struct fstab_rec *fstab);
int fs_mgr_is_verified(const struct fstab_rec *fstab);
+int fs_mgr_is_verifyatboot(const struct fstab_rec *fstab);
int fs_mgr_is_encryptable(const struct fstab_rec *fstab);
int fs_mgr_is_file_encrypted(const struct fstab_rec *fstab);
const char* fs_mgr_get_file_encryption_mode(const struct fstab_rec *fstab);
@@ -131,10 +135,10 @@
int fs_mgr_do_format(struct fstab_rec *fstab, bool reserve_footer);
-#define FS_MGR_EARLY_SETUP_VERITY_NO_VERITY -2
-#define FS_MGR_EARLY_SETUP_VERITY_FAIL -1
-#define FS_MGR_EARLY_SETUP_VERITY_SUCCESS 0
-int fs_mgr_early_setup_verity(struct fstab_rec *fstab);
+#define FS_MGR_SETUP_VERITY_DISABLED (-2)
+#define FS_MGR_SETUP_VERITY_FAIL (-1)
+#define FS_MGR_SETUP_VERITY_SUCCESS 0
+int fs_mgr_setup_verity(struct fstab_rec *fstab, bool wait_for_verity_dev);
#ifdef __cplusplus
}
diff --git a/init/Android.mk b/init/Android.mk
index a10a714..18cbedc 100644
--- a/init/Android.mk
+++ b/init/Android.mk
@@ -123,6 +123,7 @@
LOCAL_MODULE := init_tests
LOCAL_SRC_FILES := \
init_parser_test.cpp \
+ property_service_test.cpp \
util_test.cpp \
LOCAL_SHARED_LIBRARIES += \
diff --git a/init/builtins.cpp b/init/builtins.cpp
index 2388edc..6dd1cbb 100644
--- a/init/builtins.cpp
+++ b/init/builtins.cpp
@@ -476,15 +476,18 @@
static void import_late(const std::vector<std::string>& args, size_t start_index, size_t end_index) {
Parser& parser = Parser::GetInstance();
if (end_index <= start_index) {
- // Use the default set if no path is given
- static const std::vector<std::string> init_directories = {
- "/system/etc/init",
- "/vendor/etc/init",
- "/odm/etc/init"
- };
-
- for (const auto& dir : init_directories) {
- parser.ParseConfig(dir);
+ // Fallbacks for partitions on which early mount isn't enabled.
+ if (!parser.is_system_etc_init_loaded()) {
+ parser.ParseConfig("/system/etc/init");
+ parser.set_is_system_etc_init_loaded(true);
+ }
+ if (!parser.is_vendor_etc_init_loaded()) {
+ parser.ParseConfig("/vendor/etc/init");
+ parser.set_is_vendor_etc_init_loaded(true);
+ }
+ if (!parser.is_odm_etc_init_loaded()) {
+ parser.ParseConfig("/odm/etc/init");
+ parser.set_is_odm_etc_init_loaded(true);
}
} else {
for (size_t i = start_index; i < end_index; ++i) {
diff --git a/init/devices.cpp b/init/devices.cpp
index b3b808b..bd11f5f 100644
--- a/init/devices.cpp
+++ b/init/devices.cpp
@@ -251,7 +251,10 @@
* some device nodes, so the uid has to be set with chown() and is still
* racy. Fixing the gid race at least fixed the issue with system_server
* opening dynamic input devices under the AID_INPUT gid. */
- setegid(gid);
+ if (setegid(gid)) {
+ PLOG(ERROR) << "setegid(" << gid << ") for " << path << " device failed";
+ goto out;
+ }
/* If the node already exists update its SELinux label to handle cases when
* it was created with the wrong context during coldboot procedure. */
if (mknod(path, mode, dev) && (errno == EEXIST) && secontext) {
@@ -273,7 +276,9 @@
out:
chown(path, uid, -1);
- setegid(AID_ROOT);
+ if (setegid(AID_ROOT)) {
+ PLOG(FATAL) << "setegid(AID_ROOT) failed";
+ }
if (secontext) {
freecon(secontext);
@@ -999,15 +1004,20 @@
}
void device_init(const char* path, coldboot_callback fn) {
- sehandle = selinux_android_file_context_handle();
- selinux_status_open(true);
-
- /* is 256K enough? udev uses 16MB! */
- device_fd.reset(uevent_open_socket(256*1024, true));
- if (device_fd == -1) {
- return;
+ if (!sehandle) {
+ sehandle = selinux_android_file_context_handle();
}
- fcntl(device_fd, F_SETFL, O_NONBLOCK);
+ // open uevent socket and selinux status only if it hasn't been
+ // done before
+ if (device_fd == -1) {
+ /* is 256K enough? udev uses 16MB! */
+ device_fd.reset(uevent_open_socket(256 * 1024, true));
+ if (device_fd == -1) {
+ return;
+ }
+ fcntl(device_fd, F_SETFL, O_NONBLOCK);
+ selinux_status_open(true);
+ }
if (access(COLDBOOT_DONE, F_OK) == 0) {
LOG(VERBOSE) << "Skipping coldboot, already done!";
@@ -1040,6 +1050,7 @@
void device_close() {
destroy_platform_devices();
device_fd.reset();
+ selinux_status_close();
}
int get_device_fd() {
diff --git a/init/init.cpp b/init/init.cpp
index 7f7eb2f..9b14467 100644
--- a/init/init.cpp
+++ b/init/init.cpp
@@ -502,26 +502,30 @@
std::string dt_value;
std::string file_name = StringPrintf("%s/compatible", android_dt_dir);
- android::base::ReadFileToString(file_name, &dt_value);
- if (!dt_value.compare("android,firmware")) {
- LOG(ERROR) << "firmware/android is not compatible with 'android,firmware'";
- return false;
+ if (android::base::ReadFileToString(file_name, &dt_value)) {
+ // trim the trailing '\0' out, otherwise the comparison
+ // will produce false-negatives.
+ dt_value.resize(dt_value.size() - 1);
+ if (dt_value == "android,firmware") {
+ return true;
+ }
}
- return true;
+ return false;
}
static bool is_dt_fstab_compatible() {
std::string dt_value;
std::string file_name = StringPrintf("%s/%s/compatible", android_dt_dir, "fstab");
- android::base::ReadFileToString(file_name, &dt_value);
- if (!dt_value.compare("android,fstab")) {
- LOG(ERROR) << "firmware/android/fstab is not compatible with 'android,fstab'";
- return false;
+ if (android::base::ReadFileToString(file_name, &dt_value)) {
+ dt_value.resize(dt_value.size() - 1);
+ if (dt_value == "android,fstab") {
+ return true;
+ }
}
- return true;
+ return false;
}
static void process_kernel_dt() {
@@ -664,101 +668,56 @@
}
}
-static std::string import_dt_fstab() {
- std::string fstab;
- if (!is_dt_compatible() || !is_dt_fstab_compatible()) {
- return fstab;
+static bool early_mount_one(struct fstab_rec* rec) {
+ if (rec && fs_mgr_is_verified(rec)) {
+ // setup verity and create the dm-XX block device
+ // needed to mount this partition
+ int ret = fs_mgr_setup_verity(rec, false);
+ if (ret == FS_MGR_SETUP_VERITY_FAIL) {
+ PLOG(ERROR) << "early_mount: Failed to setup verity for '" << rec->mount_point << "'";
+ return false;
+ }
+
+ // The exact block device name is added as a mount source by
+ // fs_mgr_setup_verity() in ->blk_device as "/dev/block/dm-XX"
+ // We create that device by running coldboot on /sys/block/dm-XX
+ std::string dm_device(basename(rec->blk_device));
+ std::string syspath = StringPrintf("/sys/block/%s", dm_device.c_str());
+ device_init(syspath.c_str(), [&](uevent* uevent) -> coldboot_action_t {
+ if (uevent->device_name && !strcmp(dm_device.c_str(), uevent->device_name)) {
+ LOG(VERBOSE) << "early_mount: creating dm-verity device : " << dm_device;
+ return COLDBOOT_STOP;
+ }
+ return COLDBOOT_CONTINUE;
+ });
}
- std::string fstabdir_name = StringPrintf("%s/fstab", android_dt_dir);
- std::unique_ptr<DIR, int (*)(DIR*)> fstabdir(opendir(fstabdir_name.c_str()), closedir);
- if (!fstabdir) return fstab;
-
- dirent* dp;
- while ((dp = readdir(fstabdir.get())) != NULL) {
- // skip over name and compatible
- if (dp->d_type != DT_DIR) {
- continue;
- }
-
- // skip if its not 'vendor', 'odm' or 'system'
- if (strcmp(dp->d_name, "odm") && strcmp(dp->d_name, "system") &&
- strcmp(dp->d_name, "vendor")) {
- continue;
- }
-
- // create <dev> <mnt_point> <type> <mnt_flags> <fsmgr_flags>\n
- std::vector<std::string> fstab_entry;
- std::string file_name;
- std::string value;
- file_name = StringPrintf("%s/%s/dev", fstabdir_name.c_str(), dp->d_name);
- if (!android::base::ReadFileToString(file_name, &value)) {
- LOG(ERROR) << "dt_fstab: Failed to find device for partition " << dp->d_name;
- fstab.clear();
- break;
- }
- // trim the terminating '\0' out
- value.resize(value.size() - 1);
- fstab_entry.push_back(value);
- fstab_entry.push_back(StringPrintf("/%s", dp->d_name));
-
- file_name = StringPrintf("%s/%s/type", fstabdir_name.c_str(), dp->d_name);
- if (!android::base::ReadFileToString(file_name, &value)) {
- LOG(ERROR) << "dt_fstab: Failed to find type for partition " << dp->d_name;
- fstab.clear();
- break;
- }
- value.resize(value.size() - 1);
- fstab_entry.push_back(value);
-
- file_name = StringPrintf("%s/%s/mnt_flags", fstabdir_name.c_str(), dp->d_name);
- if (!android::base::ReadFileToString(file_name, &value)) {
- LOG(ERROR) << "dt_fstab: Failed to find type for partition " << dp->d_name;
- fstab.clear();
- break;
- }
- value.resize(value.size() - 1);
- fstab_entry.push_back(value);
-
- file_name = StringPrintf("%s/%s/fsmgr_flags", fstabdir_name.c_str(), dp->d_name);
- if (!android::base::ReadFileToString(file_name, &value)) {
- LOG(ERROR) << "dt_fstab: Failed to find type for partition " << dp->d_name;
- fstab.clear();
- break;
- }
- value.resize(value.size() - 1);
- fstab_entry.push_back(value);
-
- fstab += android::base::Join(fstab_entry, " ");
- fstab += '\n';
+ if (rec && fs_mgr_do_mount_one(rec)) {
+ PLOG(ERROR) << "early_mount: Failed to mount '" << rec->mount_point << "'";
+ return false;
}
- return fstab;
+ return true;
}
/* Early mount vendor and ODM partitions. The fstab is read from device-tree. */
static bool early_mount() {
- std::string fstab = import_dt_fstab();
- if (fstab.empty()) {
- LOG(INFO) << "Early mount skipped (missing fstab in device tree)";
+ // first check if device tree fstab entries are compatible
+ if (!is_dt_fstab_compatible()) {
+ LOG(INFO) << "Early mount skipped (missing/incompatible fstab in device tree)";
return true;
}
- std::unique_ptr<FILE, decltype(&fclose)> fstab_file(
- fmemopen(static_cast<void*>(const_cast<char*>(fstab.c_str())), fstab.length(), "r"), fclose);
- if (!fstab_file) {
- PLOG(ERROR) << "Early mount failed to open fstab file in memory";
- return false;
- }
-
- std::unique_ptr<struct fstab, decltype(&fs_mgr_free_fstab)> tab(
- fs_mgr_read_fstab_file(fstab_file.get()), fs_mgr_free_fstab);
+ std::unique_ptr<fstab, decltype(&fs_mgr_free_fstab)> tab(
+ fs_mgr_read_fstab_dt(), fs_mgr_free_fstab);
if (!tab) {
- LOG(ERROR) << "Early mount fsmgr failed to load fstab from kernel:" << std::endl << fstab;
+ LOG(ERROR) << "Early mount failed to read fstab from device tree";
return false;
}
// find out fstab records for odm, system and vendor
+ // TODO: add std::map<std::string, fstab_rec*> so all required information about
+ // them can be gathered at once in a single loop
fstab_rec* odm_rec = fs_mgr_get_entry_for_mount_point(tab.get(), "/odm");
fstab_rec* system_rec = fs_mgr_get_entry_for_mount_point(tab.get(), "/system");
fstab_rec* vendor_rec = fs_mgr_get_entry_for_mount_point(tab.get(), "/vendor");
@@ -767,13 +726,41 @@
return true;
}
+ // don't allow verifyatboot for early mounted partitions
+ if ((odm_rec && fs_mgr_is_verifyatboot(odm_rec)) ||
+ (system_rec && fs_mgr_is_verifyatboot(system_rec)) ||
+ (vendor_rec && fs_mgr_is_verifyatboot(vendor_rec))) {
+ LOG(ERROR) << "Early mount partitions can't be verified at boot";
+ return false;
+ }
+
// assume A/B device if we find 'slotselect' in any fstab entry
bool is_ab = ((odm_rec && fs_mgr_is_slotselect(odm_rec)) ||
(system_rec && fs_mgr_is_slotselect(system_rec)) ||
(vendor_rec && fs_mgr_is_slotselect(vendor_rec)));
+
+ // check for verified partitions
+ bool need_verity = ((odm_rec && fs_mgr_is_verified(odm_rec)) ||
+ (system_rec && fs_mgr_is_verified(system_rec)) ||
+ (vendor_rec && fs_mgr_is_verified(vendor_rec)));
+
+ // check if verity metadata is on a separate partition and get partition
+ // name from the end of the ->verity_loc path. verity state is not partition
+ // specific, so there must be only 1 additional partition that carries
+ // verity state.
+ std::string meta_partition;
+ if (odm_rec && odm_rec->verity_loc) {
+ meta_partition = basename(odm_rec->verity_loc);
+ } else if (system_rec && system_rec->verity_loc) {
+ meta_partition = basename(system_rec->verity_loc);
+ } else if (vendor_rec && vendor_rec->verity_loc) {
+ meta_partition = basename(vendor_rec->verity_loc);
+ }
+
bool found_odm = !odm_rec;
bool found_system = !system_rec;
bool found_vendor = !vendor_rec;
+ bool found_meta = meta_partition.empty();
int count_odm = 0, count_vendor = 0, count_system = 0;
// create the devices we need..
@@ -802,9 +789,7 @@
// wait twice for A/B-ed partitions
count_odm++;
- if (!is_ab) {
- found_odm = true;
- } else if (count_odm == 2) {
+ if (!is_ab || count_odm == 2) {
found_odm = true;
}
@@ -813,9 +798,7 @@
LOG(VERBOSE) << "early_mount: found (" << uevent->partition_name << ") partition";
count_system++;
- if (!is_ab) {
- found_system = true;
- } else if (count_system == 2) {
+ if (!is_ab || count_system == 2) {
found_system = true;
}
@@ -823,13 +806,15 @@
} else if (!found_vendor && !strncmp(uevent->partition_name, "vendor", 6)) {
LOG(VERBOSE) << "early_mount: found (" << uevent->partition_name << ") partition";
count_vendor++;
- if (!is_ab) {
- found_vendor = true;
- } else if (count_vendor == 2) {
+ if (!is_ab || count_vendor == 2) {
found_vendor = true;
}
create_this_node = true;
+ } else if (!found_meta && (meta_partition == uevent->partition_name)) {
+ LOG(VERBOSE) << "early_mount: found (" << uevent->partition_name << ") partition";
+ found_meta = true;
+ create_this_node = true;
}
}
@@ -837,7 +822,7 @@
// node and stop coldboot. If this is a prefix matched
// partition, create device node and continue. For everything
// else skip the device node
- if (found_odm && found_system && found_vendor) {
+ if (found_meta && found_odm && found_system && found_vendor) {
ret = COLDBOOT_STOP;
} else if (create_this_node) {
ret = COLDBOOT_CREATE;
@@ -848,24 +833,20 @@
return ret;
});
- // TODO: add support to mount partitions w/ verity
-
- int ret = 0;
- if (odm_rec &&
- (ret = fs_mgr_do_mount(tab.get(), odm_rec->mount_point, odm_rec->blk_device, NULL))) {
- PLOG(ERROR) << "early_mount: fs_mgr_do_mount returned error for mounting odm";
- return false;
+ if (need_verity) {
+ // create /dev/device mapper
+ device_init("/sys/devices/virtual/misc/device-mapper",
+ [&](uevent* uevent) -> coldboot_action_t { return COLDBOOT_STOP; });
}
- if (vendor_rec &&
- (ret = fs_mgr_do_mount(tab.get(), vendor_rec->mount_point, vendor_rec->blk_device, NULL))) {
- PLOG(ERROR) << "early_mount: fs_mgr_do_mount returned error for mounting vendor";
- return false;
- }
+ bool success = true;
+ if (odm_rec && !(success = early_mount_one(odm_rec))) goto done;
+ if (system_rec && !(success = early_mount_one(system_rec))) goto done;
+ if (vendor_rec && !(success = early_mount_one(vendor_rec))) goto done;
+done:
device_close();
-
- return true;
+ return success;
}
int main(int argc, char** argv) {
@@ -1011,8 +992,16 @@
std::string bootscript = property_get("ro.boot.init_rc");
if (bootscript.empty()) {
parser.ParseConfig("/init.rc");
+ parser.set_is_system_etc_init_loaded(
+ parser.ParseConfig("/system/etc/init"));
+ parser.set_is_vendor_etc_init_loaded(
+ parser.ParseConfig("/vendor/etc/init"));
+ parser.set_is_odm_etc_init_loaded(parser.ParseConfig("/odm/etc/init"));
} else {
parser.ParseConfig(bootscript);
+ parser.set_is_system_etc_init_loaded(true);
+ parser.set_is_vendor_etc_init_loaded(true);
+ parser.set_is_odm_etc_init_loaded(true);
}
ActionManager& am = ActionManager::GetInstance();
diff --git a/init/init_parser.h b/init/init_parser.h
index 5ed30ad..f66ba52 100644
--- a/init/init_parser.h
+++ b/init/init_parser.h
@@ -41,6 +41,18 @@
bool ParseConfig(const std::string& path);
void AddSectionParser(const std::string& name,
std::unique_ptr<SectionParser> parser);
+ void set_is_system_etc_init_loaded(bool loaded) {
+ is_system_etc_init_loaded_ = loaded;
+ }
+ void set_is_vendor_etc_init_loaded(bool loaded) {
+ is_vendor_etc_init_loaded_ = loaded;
+ }
+ void set_is_odm_etc_init_loaded(bool loaded) {
+ is_odm_etc_init_loaded_ = loaded;
+ }
+ bool is_system_etc_init_loaded() { return is_system_etc_init_loaded_; }
+ bool is_vendor_etc_init_loaded() { return is_vendor_etc_init_loaded_; }
+ bool is_odm_etc_init_loaded() { return is_odm_etc_init_loaded_; }
private:
Parser();
@@ -50,6 +62,9 @@
bool ParseConfigDir(const std::string& path);
std::map<std::string, std::unique_ptr<SectionParser>> section_parsers_;
+ bool is_system_etc_init_loaded_ = false;
+ bool is_vendor_etc_init_loaded_ = false;
+ bool is_odm_etc_init_loaded_ = false;
};
#endif
diff --git a/init/property_service.cpp b/init/property_service.cpp
index ce197ee..04bcb18 100644
--- a/init/property_service.cpp
+++ b/init/property_service.cpp
@@ -245,6 +245,13 @@
return true;
}
+ // http://b/35166374: don't allow init to make arbitrarily large allocations.
+ if (len > 0xffff) {
+ LOG(ERROR) << "sys_prop: RecvString asked to read huge string: " << len;
+ errno = ENOMEM;
+ return false;
+ }
+
std::vector<char> chars(len);
if (!RecvChars(&chars[0], len, timeout_ms)) {
return false;
@@ -386,12 +393,11 @@
return;
}
- /* Check socket options here */
struct ucred cr;
socklen_t cr_size = sizeof(cr);
if (getsockopt(s, SOL_SOCKET, SO_PEERCRED, &cr, &cr_size) < 0) {
close(s);
- PLOG(ERROR) << "Unable to receive socket options";
+ PLOG(ERROR) << "sys_prop: unable to get SO_PEERCRED";
return;
}
@@ -399,14 +405,13 @@
uint32_t timeout_ms = kDefaultSocketTimeout;
uint32_t cmd = 0;
-
if (!socket.RecvUint32(&cmd, &timeout_ms)) {
PLOG(ERROR) << "sys_prop: error while reading command from the socket";
socket.SendUint32(PROP_ERROR_READ_CMD);
return;
}
- switch(cmd) {
+ switch (cmd) {
case PROP_MSG_SETPROP: {
char prop_name[PROP_NAME_MAX];
char prop_value[PROP_VALUE_MAX];
@@ -437,7 +442,9 @@
handle_property_set(socket, name, value, false);
break;
}
+
default:
+ LOG(ERROR) << "sys_prop: invalid command " << cmd;
socket.SendUint32(PROP_ERROR_INVALID_CMD);
break;
}
diff --git a/init/property_service_test.cpp b/init/property_service_test.cpp
new file mode 100644
index 0000000..4d784aa
--- /dev/null
+++ b/init/property_service_test.cpp
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2017 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>
+#include <sys/socket.h>
+#include <sys/un.h>
+
+#define _REALLY_INCLUDE_SYS__SYSTEM_PROPERTIES_H_
+#include <sys/_system_properties.h>
+
+#include <gtest/gtest.h>
+
+TEST(property_service, very_long_name_35166374) {
+ // Connect to the property service directly...
+ int fd = socket(AF_LOCAL, SOCK_STREAM | SOCK_CLOEXEC, 0);
+ ASSERT_NE(fd, -1);
+
+ static const char* property_service_socket = "/dev/socket/" PROP_SERVICE_NAME;
+ sockaddr_un addr = {};
+ addr.sun_family = AF_LOCAL;
+ strlcpy(addr.sun_path, property_service_socket, sizeof(addr.sun_path));
+
+ socklen_t addr_len = strlen(property_service_socket) + offsetof(sockaddr_un, sun_path) + 1;
+ ASSERT_NE(connect(fd, reinterpret_cast<sockaddr*>(&addr), addr_len), -1);
+
+ // ...so we can send it a malformed request.
+ uint32_t msg = PROP_MSG_SETPROP2;
+ uint32_t size = 0xffffffff;
+ uint32_t data = 0xdeadbeef;
+
+ ASSERT_EQ(static_cast<ssize_t>(sizeof(msg)), send(fd, &msg, sizeof(msg), 0));
+ ASSERT_EQ(static_cast<ssize_t>(sizeof(size)), send(fd, &size, sizeof(size), 0));
+ ASSERT_EQ(static_cast<ssize_t>(sizeof(data)), send(fd, &data, sizeof(data), 0));
+ ASSERT_EQ(0, close(fd));
+}
diff --git a/libcutils/fs_config.c b/libcutils/fs_config.c
index 7e27c3e..75e2492 100644
--- a/libcutils/fs_config.c
+++ b/libcutils/fs_config.c
@@ -180,6 +180,7 @@
{ 00755, AID_ROOT, AID_SHELL, 0, "system/bin/crash_dump32" },
{ 00755, AID_ROOT, AID_SHELL, 0, "system/bin/crash_dump64" },
{ 00755, AID_ROOT, AID_SHELL, 0, "system/bin/debuggerd" },
+ { 00700, AID_ROOT, AID_ROOT, 0, "system/bin/secilc" },
{ 00750, AID_ROOT, AID_ROOT, 0, "system/bin/uncrypt" },
{ 00750, AID_ROOT, AID_ROOT, 0, "system/bin/install-recovery.sh" },
{ 00755, AID_ROOT, AID_SHELL, 0, "system/bin/*" },
diff --git a/liblog/logprint.c b/liblog/logprint.c
index e61850d..af52528 100644
--- a/liblog/logprint.c
+++ b/liblog/logprint.c
@@ -625,14 +625,14 @@
}
static bool findChar(const char** cp, size_t* len, int c) {
- while (*len && isspace(**cp)) {
- ++*cp;
- --*len;
+ while ((*len) && isspace(*(*cp))) {
+ ++(*cp);
+ --(*len);
}
if (c == INT_MAX) return *len;
- if (*len && (**cp == c)) {
- ++*cp;
- --*len;
+ if ((*len) && (*(*cp) == c)) {
+ ++(*cp);
+ --(*len);
return true;
}
return false;
@@ -991,7 +991,7 @@
LIBLOG_ABI_PUBLIC int android_log_processBinaryLogBuffer(
struct logger_entry *buf,
AndroidLogEntry *entry,
- const EventTagMap *map __unused,
+ const EventTagMap *map __unused, // only on !__ANDROID__
char *messageBuf, int messageBufLen)
{
size_t inCount;
diff --git a/libutils/include/utils/Condition.h b/libutils/include/utils/Condition.h
index 25a53aa..2c80acd 100644
--- a/libutils/include/utils/Condition.h
+++ b/libutils/include/utils/Condition.h
@@ -86,19 +86,22 @@
#if !defined(_WIN32)
-inline Condition::Condition() {
- pthread_cond_init(&mCond, NULL);
+inline Condition::Condition() : Condition(PRIVATE) {
}
inline Condition::Condition(int type) {
+ pthread_condattr_t attr;
+ pthread_condattr_init(&attr);
+#if defined(__linux__)
+ pthread_condattr_setclock(&attr, CLOCK_MONOTONIC);
+#endif
+
if (type == SHARED) {
- pthread_condattr_t attr;
- pthread_condattr_init(&attr);
pthread_condattr_setpshared(&attr, PTHREAD_PROCESS_SHARED);
- pthread_cond_init(&mCond, &attr);
- pthread_condattr_destroy(&attr);
- } else {
- pthread_cond_init(&mCond, NULL);
}
+
+ pthread_cond_init(&mCond, &attr);
+ pthread_condattr_destroy(&attr);
+
}
inline Condition::~Condition() {
pthread_cond_destroy(&mCond);
@@ -109,7 +112,7 @@
inline status_t Condition::waitRelative(Mutex& mutex, nsecs_t reltime) {
struct timespec ts;
#if defined(__linux__)
- clock_gettime(CLOCK_REALTIME, &ts);
+ clock_gettime(CLOCK_MONOTONIC, &ts);
#else // __APPLE__
// Apple doesn't support POSIX clocks.
struct timeval t;
diff --git a/libutils/include/utils/Singleton.h b/libutils/include/utils/Singleton.h
index 7cc4c18..a989a47 100644
--- a/libutils/include/utils/Singleton.h
+++ b/libutils/include/utils/Singleton.h
@@ -26,6 +26,16 @@
namespace android {
// ---------------------------------------------------------------------------
+// Singleton<TYPE> may be used in multiple libraries, only one of which should
+// define the static member variables using ANDROID_SINGLETON_STATIC_INSTANCE.
+// Turn off -Wundefined-var-template so other users don't get:
+// instantiation of variable 'android::Singleton<TYPE>::sLock' required here,
+// but no definition is available
+#if defined(__clang__)
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wundefined-var-template"
+#endif
+
template <typename TYPE>
class ANDROID_API Singleton
{
@@ -56,11 +66,9 @@
static TYPE* sInstance;
};
-template <typename TYPE>
-Mutex Singleton<TYPE>::sLock;
-
-template <typename TYPE>
-TYPE* Singleton<TYPE>::sInstance;
+#if defined(__clang__)
+#pragma clang diagnostic pop
+#endif
/*
* use ANDROID_SINGLETON_STATIC_INSTANCE(TYPE) in your implementation file
diff --git a/libutils/tests/Android.bp b/libutils/tests/Android.bp
index ec6b67f..70ada72 100644
--- a/libutils/tests/Android.bp
+++ b/libutils/tests/Android.bp
@@ -18,33 +18,49 @@
cc_test {
name: "libutils_tests",
+ host_supported: true,
srcs: [
- "BlobCache_test.cpp",
"BitSet_test.cpp",
- "Looper_test.cpp",
"LruCache_test.cpp",
- "RefBase_test.cpp",
"String8_test.cpp",
"StrongPointer_test.cpp",
- "SystemClock_test.cpp",
"Unicode_test.cpp",
"Vector_test.cpp",
],
- shared_libs: [
- "libz",
- "liblog",
- "libcutils",
- "libutils",
- ],
-}
+ target: {
+ android: {
+ srcs: [
+ "BlobCache_test.cpp",
+ "Looper_test.cpp",
+ "RefBase_test.cpp",
+ "SystemClock_test.cpp",
+ ],
+ shared_libs: [
+ "libz",
+ "liblog",
+ "libcutils",
+ "libutils",
+ ],
+ },
+ linux: {
+ srcs: [
+ "Looper_test.cpp",
+ "RefBase_test.cpp",
+ ],
+ },
+ host: {
+ static_libs: [
+ "libutils",
+ "liblog",
+ ],
+ },
+ },
-cc_test_host {
- name: "libutils_tests_host",
- srcs: ["Vector_test.cpp"],
- static_libs: [
- "libutils",
- "liblog",
+ cflags: [
+ "-Wall",
+ "-Wextra",
+ "-Werror",
],
}
diff --git a/libutils/tests/StrongPointer_test.cpp b/libutils/tests/StrongPointer_test.cpp
index 323a6f2..153cf96 100644
--- a/libutils/tests/StrongPointer_test.cpp
+++ b/libutils/tests/StrongPointer_test.cpp
@@ -21,13 +21,13 @@
using namespace android;
-class Foo : public LightRefBase<Foo> {
+class SPFoo : public LightRefBase<SPFoo> {
public:
- explicit Foo(bool* deleted_check) : mDeleted(deleted_check) {
+ explicit SPFoo(bool* deleted_check) : mDeleted(deleted_check) {
*mDeleted = false;
}
- ~Foo() {
+ ~SPFoo() {
*mDeleted = true;
}
private:
@@ -36,13 +36,13 @@
TEST(StrongPointer, move) {
bool isDeleted;
- Foo* foo = new Foo(&isDeleted);
+ SPFoo* foo = new SPFoo(&isDeleted);
ASSERT_EQ(0, foo->getStrongCount());
ASSERT_FALSE(isDeleted) << "Already deleted...?";
- sp<Foo> sp1(foo);
+ sp<SPFoo> sp1(foo);
ASSERT_EQ(1, foo->getStrongCount());
{
- sp<Foo> sp2 = std::move(sp1);
+ sp<SPFoo> sp2 = std::move(sp1);
ASSERT_EQ(1, foo->getStrongCount()) << "std::move failed, incremented refcnt";
ASSERT_EQ(nullptr, sp1.get()) << "std::move failed, sp1 is still valid";
// The strong count isn't increasing, let's double check the old object
@@ -52,7 +52,7 @@
ASSERT_FALSE(isDeleted) << "deleted too early! still has a reference!";
{
// Now let's double check it deletes on time
- sp<Foo> sp2 = std::move(sp1);
+ sp<SPFoo> sp2 = std::move(sp1);
}
ASSERT_TRUE(isDeleted) << "foo was leaked!";
}
diff --git a/logd/CommandListener.cpp b/logd/CommandListener.cpp
index 74e0ea5..6ad7351 100644
--- a/logd/CommandListener.cpp
+++ b/logd/CommandListener.cpp
@@ -301,6 +301,7 @@
const char *name = NULL;
const char *format = NULL;
+ const char *id = NULL;
for (int i = 1; i < argc; ++i) {
static const char _name[] = "name=";
if (!strncmp(argv[i], _name, strlen(_name))) {
@@ -313,6 +314,21 @@
format = argv[i] + strlen(_format);
continue;
}
+
+ static const char _id[] = "id=";
+ if (!strncmp(argv[i], _id, strlen(_id))) {
+ id = argv[i] + strlen(_id);
+ continue;
+ }
+ }
+
+ if (id) {
+ if (format || name) {
+ cli->sendMsg("can not mix id= with either format= or name=");
+ return 0;
+ }
+ cli->sendMsg(package_string(mBuf.formatEntry(atoi(id), uid)).c_str());
+ return 0;
}
cli->sendMsg(package_string(mBuf.formatGetEventTag(uid,
diff --git a/logd/LogBuffer.h b/logd/LogBuffer.h
index da63e12..9feef32 100644
--- a/logd/LogBuffer.h
+++ b/logd/LogBuffer.h
@@ -140,6 +140,9 @@
const char *name, const char *format) {
return tags.formatGetEventTag(uid, name, format);
}
+ std::string formatEntry(uint32_t tag, uid_t uid) {
+ return tags.formatEntry(tag, uid);
+ }
const char *tagToName(uint32_t tag) { return tags.tagToName(tag); }
// helper must be protected directly or implicitly by lock()/unlock()
diff --git a/logd/LogTags.cpp b/logd/LogTags.cpp
index a109592..64aa219 100644
--- a/logd/LogTags.cpp
+++ b/logd/LogTags.cpp
@@ -836,6 +836,11 @@
return ret;
}
+std::string LogTags::formatEntry(uint32_t tag, uid_t uid) {
+ android::RWLock::AutoRLock readLock(rwlock);
+ return formatEntry_locked(tag, uid);
+}
+
std::string LogTags::formatGetEventTag(uid_t uid,
const char* name, const char* format) {
bool all = name && (name[0] == '*') && !name[1];
diff --git a/logd/LogTags.h b/logd/LogTags.h
index 37a6d96..4457c46 100644
--- a/logd/LogTags.h
+++ b/logd/LogTags.h
@@ -106,6 +106,7 @@
// reverse lookup from tag
const char* tagToName(uint32_t tag) const;
const char* tagToFormat(uint32_t tag) const;
+ std::string formatEntry(uint32_t tag, uid_t uid);
// find associated tag
uint32_t nameToTag(const char* name) const;
diff --git a/logd/tests/logd_test.cpp b/logd/tests/logd_test.cpp
index adf583b..8a35059 100644
--- a/logd/tests/logd_test.cpp
+++ b/logd/tests/logd_test.cpp
@@ -836,6 +836,23 @@
#endif
}
+TEST(logd, getEventTag_42) {
+#ifdef __ANDROID__
+ char buffer[256];
+ memset(buffer, 0, sizeof(buffer));
+ snprintf(buffer, sizeof(buffer), "getEventTag id=42");
+ send_to_control(buffer, sizeof(buffer));
+ buffer[sizeof(buffer) - 1] = '\0';
+ char *cp;
+ long ret = strtol(buffer, &cp, 10);
+ EXPECT_GT(ret, 16);
+ EXPECT_TRUE(strstr(buffer, "\t(to life the universe etc|3)") != NULL);
+ EXPECT_TRUE(strstr(buffer, "answer") != NULL);
+#else
+ GTEST_LOG_(INFO) << "This test does nothing.\n";
+#endif
+}
+
TEST(logd, getEventTag_newentry) {
#ifdef __ANDROID__
char buffer[256];