Merge "check ext4 magic before running next steps"
diff --git a/adb/Android.mk b/adb/Android.mk
index e841205..d17b063 100644
--- a/adb/Android.mk
+++ b/adb/Android.mk
@@ -81,12 +81,14 @@
LIBADB_darwin_SRC_FILES := \
sysdeps_unix.cpp \
+ sysdeps/posix/network.cpp \
client/usb_dispatch.cpp \
client/usb_libusb.cpp \
client/usb_osx.cpp \
LIBADB_linux_SRC_FILES := \
sysdeps_unix.cpp \
+ sysdeps/posix/network.cpp \
client/usb_dispatch.cpp \
client/usb_libusb.cpp \
client/usb_linux.cpp \
@@ -123,6 +125,7 @@
$(LIBADB_SRC_FILES) \
adbd_auth.cpp \
jdwp_service.cpp \
+ sysdeps/posix/network.cpp \
LOCAL_SANITIZE := $(adb_target_sanitize)
@@ -217,9 +220,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 \
diff --git a/adb/client/usb_linux.cpp b/adb/client/usb_linux.cpp
index 13b7674..3a45dbd 100644
--- a/adb/client/usb_linux.cpp
+++ b/adb/client/usb_linux.cpp
@@ -574,7 +574,7 @@
register_usb_transport(done_usb, serial.c_str(), dev_path, done_usb->writeable);
}
-static void device_poll_thread(void*) {
+static void device_poll_thread() {
adb_thread_setname("device poll");
D("Created device thread");
while (true) {
@@ -593,8 +593,6 @@
actions.sa_handler = [](int) {};
sigaction(SIGALRM, &actions, nullptr);
- if (!adb_thread_create(device_poll_thread, nullptr)) {
- fatal_errno("cannot create device_poll thread");
- }
+ std::thread(device_poll_thread).detach();
}
} // namespace native
diff --git a/adb/client/usb_osx.cpp b/adb/client/usb_osx.cpp
index d4fc7c0..8713b2c 100644
--- a/adb/client/usb_osx.cpp
+++ b/adb/client/usb_osx.cpp
@@ -405,7 +405,7 @@
std::mutex& operate_device_lock = *new std::mutex();
-static void RunLoopThread(void* unused) {
+static void RunLoopThread() {
adb_thread_setname("RunLoop");
VLOG(USB) << "RunLoopThread started";
@@ -436,9 +436,7 @@
usb_inited_flag = false;
- if (!adb_thread_create(RunLoopThread, nullptr)) {
- fatal_errno("cannot create RunLoop thread");
- }
+ std::thread(RunLoopThread).detach();
// Wait for initialization to finish
while (!usb_inited_flag) {
diff --git a/adb/client/usb_windows.cpp b/adb/client/usb_windows.cpp
index 640e91e..9e00a5d 100644
--- a/adb/client/usb_windows.cpp
+++ b/adb/client/usb_windows.cpp
@@ -103,7 +103,7 @@
/// Entry point for thread that polls (every second) for new usb interfaces.
/// This routine calls find_devices in infinite loop.
-static void device_poll_thread(void*);
+static void device_poll_thread();
/// Initializes this module
void usb_init();
@@ -174,7 +174,7 @@
return 1;
}
-void device_poll_thread(void*) {
+void device_poll_thread() {
adb_thread_setname("Device Poll");
D("Created device thread");
@@ -203,7 +203,7 @@
return DefWindowProcW(hwnd, uMsg, wParam, lParam);
}
-static void _power_notification_thread(void*) {
+static void _power_notification_thread() {
// This uses a thread with its own window message pump to get power
// notifications. If adb runs from a non-interactive service account, this
// might not work (not sure). If that happens to not work, we could use
@@ -258,12 +258,8 @@
}
void usb_init() {
- if (!adb_thread_create(device_poll_thread, nullptr)) {
- fatal_errno("cannot create device poll thread");
- }
- if (!adb_thread_create(_power_notification_thread, nullptr)) {
- fatal_errno("cannot create power notification thread");
- }
+ std::thread(device_poll_thread).detach();
+ std::thread(_power_notification_thread).detach();
}
usb_handle* do_usb_open(const wchar_t* interface_name) {
diff --git a/adb/commandline.cpp b/adb/commandline.cpp
index ed6693c..7702b0e 100644
--- a/adb/commandline.cpp
+++ b/adb/commandline.cpp
@@ -655,13 +655,8 @@
#endif
// TODO: combine read_and_dump with stdin_read_thread to make life simpler?
- int exit_code = 1;
- if (!adb_thread_create(stdin_read_thread_loop, args)) {
- PLOG(ERROR) << "error starting stdin read thread";
- delete args;
- } else {
- exit_code = read_and_dump(fd, use_shell_protocol);
- }
+ std::thread(stdin_read_thread_loop, args).detach();
+ int exit_code = read_and_dump(fd, use_shell_protocol);
// TODO: properly exit stdin_read_thread_loop and close |fd|.
diff --git a/adb/daemon/mdns.cpp b/adb/daemon/mdns.cpp
index 7811143..849378f 100644
--- a/adb/daemon/mdns.cpp
+++ b/adb/daemon/mdns.cpp
@@ -17,12 +17,14 @@
#include "adb_mdns.h"
#include "sysdeps.h"
-#include <chrono>
#include <dns_sd.h>
#include <endian.h>
-#include <mutex>
#include <unistd.h>
+#include <chrono>
+#include <mutex>
+#include <thread>
+
#include <android-base/logging.h>
#include <android-base/properties.h>
@@ -58,7 +60,7 @@
}
}
-static void setup_mdns_thread(void* /* unused */) {
+static void setup_mdns_thread() {
start_mdns();
std::lock_guard<std::mutex> lock(mdns_lock);
@@ -88,7 +90,7 @@
void setup_mdns(int port_in) {
port = port_in;
- adb_thread_create(setup_mdns_thread, nullptr, nullptr);
+ std::thread(setup_mdns_thread).detach();
// TODO: Make this more robust against a hard kill.
atexit(teardown_mdns);
diff --git a/adb/daemon/usb.cpp b/adb/daemon/usb.cpp
index 92e9039..7e46b02 100644
--- a/adb/daemon/usb.cpp
+++ b/adb/daemon/usb.cpp
@@ -451,9 +451,7 @@
h->close = usb_ffs_close;
D("[ usb_init - starting thread ]");
- if (!adb_thread_create(usb_ffs_open_thread, h)) {
- fatal_errno("[ cannot create usb thread ]\n");
- }
+ std::thread(usb_ffs_open_thread, h).detach();
}
void usb_init() {
diff --git a/adb/fdevent_test.cpp b/adb/fdevent_test.cpp
index c933ed5..bdb973a 100644
--- a/adb/fdevent_test.cpp
+++ b/adb/fdevent_test.cpp
@@ -21,6 +21,7 @@
#include <limits>
#include <queue>
#include <string>
+#include <thread>
#include <vector>
#include "adb_io.h"
@@ -77,9 +78,9 @@
};
TEST_F(FdeventTest, fdevent_terminate) {
- adb_thread_t thread;
PrepareThread();
- ASSERT_TRUE(adb_thread_create([](void*) { fdevent_loop(); }, nullptr, &thread));
+
+ std::thread thread(fdevent_loop);
TerminateThread(thread);
}
@@ -112,7 +113,6 @@
int fd_pair2[2];
ASSERT_EQ(0, adb_socketpair(fd_pair1));
ASSERT_EQ(0, adb_socketpair(fd_pair2));
- adb_thread_t thread;
ThreadArg thread_arg;
thread_arg.first_read_fd = fd_pair1[0];
thread_arg.last_write_fd = fd_pair2[1];
@@ -121,8 +121,7 @@
int reader = fd_pair2[0];
PrepareThread();
- ASSERT_TRUE(adb_thread_create(reinterpret_cast<void (*)(void*)>(FdEventThreadFunc), &thread_arg,
- &thread));
+ std::thread thread(FdEventThreadFunc, &thread_arg);
for (size_t i = 0; i < MESSAGE_LOOP_COUNT; ++i) {
std::string read_buffer = MESSAGE;
@@ -152,7 +151,7 @@
}
}
-static void InvalidFdThreadFunc(void*) {
+static void InvalidFdThreadFunc() {
const int INVALID_READ_FD = std::numeric_limits<int>::max() - 1;
size_t happened_event_count = 0;
InvalidFdArg read_arg;
@@ -171,7 +170,6 @@
}
TEST_F(FdeventTest, invalid_fd) {
- adb_thread_t thread;
- ASSERT_TRUE(adb_thread_create(InvalidFdThreadFunc, nullptr, &thread));
- ASSERT_TRUE(adb_thread_join(thread));
+ std::thread thread(InvalidFdThreadFunc);
+ thread.join();
}
diff --git a/adb/fdevent_test.h b/adb/fdevent_test.h
index ef65b74..f4215ae 100644
--- a/adb/fdevent_test.h
+++ b/adb/fdevent_test.h
@@ -16,6 +16,8 @@
#include <gtest/gtest.h>
+#include <thread>
+
#include "socket.h"
#include "sysdeps.h"
@@ -59,10 +61,10 @@
#endif
}
- void TerminateThread(adb_thread_t thread) {
+ void TerminateThread(std::thread& thread) {
fdevent_terminate_loop();
ASSERT_TRUE(WriteFdExactly(dummy, "", 1));
- ASSERT_TRUE(adb_thread_join(thread));
+ thread.join();
ASSERT_EQ(0, adb_close(dummy));
}
};
diff --git a/adb/services.cpp b/adb/services.cpp
index 47f0a03..f764c52 100644
--- a/adb/services.cpp
+++ b/adb/services.cpp
@@ -31,6 +31,8 @@
#include <unistd.h>
#endif
+#include <thread>
+
#include <android-base/file.h>
#include <android-base/parsenetaddress.h>
#include <android-base/stringprintf.h>
@@ -259,13 +261,7 @@
sti->cookie = cookie;
sti->fd = s[1];
- if (!adb_thread_create(service_bootstrap_func, sti)) {
- free(sti);
- adb_close(s[0]);
- adb_close(s[1]);
- printf("cannot create service thread\n");
- return -1;
- }
+ std::thread(service_bootstrap_func, sti).detach();
D("service thread started, %d:%d",s[0], s[1]);
return s[0];
diff --git a/adb/shell_service.cpp b/adb/shell_service.cpp
index d4f334b..ee821f8 100644
--- a/adb/shell_service.cpp
+++ b/adb/shell_service.cpp
@@ -90,6 +90,7 @@
#include <memory>
#include <string>
+#include <thread>
#include <unordered_map>
#include <vector>
@@ -392,12 +393,7 @@
bool Subprocess::StartThread(std::unique_ptr<Subprocess> subprocess, std::string* error) {
Subprocess* raw = subprocess.release();
- if (!adb_thread_create(ThreadHandler, raw)) {
- *error =
- android::base::StringPrintf("failed to create subprocess thread: %s", strerror(errno));
- kill(raw->pid_, SIGKILL);
- return false;
- }
+ std::thread(ThreadHandler, raw).detach();
return true;
}
diff --git a/adb/socket_test.cpp b/adb/socket_test.cpp
index f56f7f7..f7c66db 100644
--- a/adb/socket_test.cpp
+++ b/adb/socket_test.cpp
@@ -42,10 +42,6 @@
class LocalSocketTest : public FdeventTest {};
-static void FdEventThreadFunc(void*) {
- fdevent_loop();
-}
-
constexpr auto SLEEP_FOR_FDEVENT = 100ms;
TEST_F(LocalSocketTest, smoke) {
@@ -88,8 +84,7 @@
connect(prev_tail, end);
PrepareThread();
- adb_thread_t thread;
- ASSERT_TRUE(adb_thread_create(FdEventThreadFunc, nullptr, &thread));
+ std::thread thread(fdevent_loop);
for (size_t i = 0; i < MESSAGE_LOOP_COUNT; ++i) {
std::string read_buffer = MESSAGE;
@@ -152,9 +147,7 @@
arg.cause_close_fd = cause_close_fd[1];
PrepareThread();
- adb_thread_t thread;
- ASSERT_TRUE(adb_thread_create(reinterpret_cast<void (*)(void*)>(CloseWithPacketThreadFunc),
- &arg, &thread));
+ std::thread thread(CloseWithPacketThreadFunc, &arg);
// Wait until the fdevent_loop() starts.
std::this_thread::sleep_for(SLEEP_FOR_FDEVENT);
ASSERT_EQ(0, adb_close(cause_close_fd[0]));
@@ -177,9 +170,7 @@
arg.cause_close_fd = cause_close_fd[1];
PrepareThread();
- adb_thread_t thread;
- ASSERT_TRUE(adb_thread_create(reinterpret_cast<void (*)(void*)>(CloseWithPacketThreadFunc),
- &arg, &thread));
+ std::thread thread(CloseWithPacketThreadFunc, &arg);
// Wait until the fdevent_loop() starts.
std::this_thread::sleep_for(SLEEP_FOR_FDEVENT);
ASSERT_EQ(0, adb_close(cause_close_fd[0]));
@@ -211,10 +202,7 @@
arg.cause_close_fd = cause_close_fd[1];
PrepareThread();
- adb_thread_t thread;
- ASSERT_TRUE(adb_thread_create(reinterpret_cast<void (*)(void*)>(CloseWithPacketThreadFunc),
- &arg, &thread));
-
+ std::thread thread(CloseWithPacketThreadFunc, &arg);
// Wait until the fdevent_loop() starts.
std::this_thread::sleep_for(SLEEP_FOR_FDEVENT);
EXPECT_EQ(2u + GetAdditionalLocalSocketCount(), fdevent_installed_count());
@@ -252,9 +240,7 @@
int listen_fd = network_inaddr_any_server(5038, SOCK_STREAM, &error);
ASSERT_GE(listen_fd, 0);
- adb_thread_t client_thread;
- ASSERT_TRUE(adb_thread_create(reinterpret_cast<void (*)(void*)>(ClientThreadFunc), nullptr,
- &client_thread));
+ std::thread client_thread(ClientThreadFunc);
int accept_fd = adb_socket_accept(listen_fd, nullptr, nullptr);
ASSERT_GE(accept_fd, 0);
@@ -262,16 +248,14 @@
arg.socket_fd = accept_fd;
PrepareThread();
- adb_thread_t thread;
- ASSERT_TRUE(adb_thread_create(reinterpret_cast<void (*)(void*)>(CloseRdHupSocketThreadFunc),
- &arg, &thread));
+ std::thread thread(CloseRdHupSocketThreadFunc, &arg);
// Wait until the fdevent_loop() starts.
std::this_thread::sleep_for(SLEEP_FOR_FDEVENT);
EXPECT_EQ(1u + GetAdditionalLocalSocketCount(), fdevent_installed_count());
// Wait until the client closes its socket.
- ASSERT_TRUE(adb_thread_join(client_thread));
+ client_thread.join();
std::this_thread::sleep_for(SLEEP_FOR_FDEVENT);
ASSERT_EQ(GetAdditionalLocalSocketCount(), fdevent_installed_count());
diff --git a/adb/sysdeps.h b/adb/sysdeps.h
index f95a855..49c7847 100644
--- a/adb/sysdeps.h
+++ b/adb/sysdeps.h
@@ -35,6 +35,7 @@
#include <android-base/utf8.h>
#include "sysdeps/errno.h"
+#include "sysdeps/network.h"
#include "sysdeps/stat.h"
/*
@@ -98,64 +99,6 @@
return c == '\\' || c == '/';
}
-typedef void (*adb_thread_func_t)(void* arg);
-typedef HANDLE adb_thread_t;
-
-struct adb_winthread_args {
- adb_thread_func_t func;
- void* arg;
-};
-
-static unsigned __stdcall adb_winthread_wrapper(void* heap_args) {
- // Move the arguments from the heap onto the thread's stack.
- adb_winthread_args thread_args = *static_cast<adb_winthread_args*>(heap_args);
- delete static_cast<adb_winthread_args*>(heap_args);
- thread_args.func(thread_args.arg);
- return 0;
-}
-
-static __inline__ bool adb_thread_create(adb_thread_func_t func, void* arg,
- adb_thread_t* thread = nullptr) {
- adb_winthread_args* args = new adb_winthread_args{.func = func, .arg = arg};
- uintptr_t handle = _beginthreadex(nullptr, 0, adb_winthread_wrapper, args, 0, nullptr);
- if (handle != static_cast<uintptr_t>(0)) {
- if (thread) {
- *thread = reinterpret_cast<HANDLE>(handle);
- } else {
- CloseHandle(thread);
- }
- return true;
- }
- return false;
-}
-
-static __inline__ bool adb_thread_join(adb_thread_t thread) {
- switch (WaitForSingleObject(thread, INFINITE)) {
- case WAIT_OBJECT_0:
- CloseHandle(thread);
- return true;
-
- case WAIT_FAILED:
- fprintf(stderr, "adb_thread_join failed: %s\n",
- android::base::SystemErrorCodeToString(GetLastError()).c_str());
- break;
-
- default:
- abort();
- }
-
- return false;
-}
-
-static __inline__ bool adb_thread_detach(adb_thread_t thread) {
- CloseHandle(thread);
- return true;
-}
-
-static __inline__ void __attribute__((noreturn)) adb_thread_exit() {
- _endthreadex(0);
-}
-
static __inline__ int adb_thread_setname(const std::string& name) {
// TODO: See https://msdn.microsoft.com/en-us/library/xcb2z8hs.aspx for how to set
// the thread name in Windows. Unfortunately, it only works during debugging, but
@@ -163,14 +106,6 @@
return 0;
}
-static __inline__ adb_thread_t adb_thread_self() {
- return GetCurrentThread();
-}
-
-static __inline__ bool adb_thread_equal(adb_thread_t lhs, adb_thread_t rhs) {
- return GetThreadId(lhs) == GetThreadId(rhs);
-}
-
static __inline__ unsigned long adb_thread_id()
{
return GetCurrentThreadId();
@@ -248,8 +183,6 @@
int unix_isatty(int fd);
#define isatty ___xxx_isatty
-int network_loopback_client(int port, int type, std::string* error);
-int network_loopback_server(int port, int type, std::string* error);
int network_inaddr_any_server(int port, int type, std::string* error);
inline int network_local_client(const char* name, int namespace_id, int type, std::string* error) {
@@ -587,17 +520,6 @@
return fd;
}
-inline int network_loopback_client(int port, int type, std::string* error) {
- return _fd_set_error_str(socket_network_client("localhost", port, type), error);
-}
-
-inline int network_loopback_server(int port, int type, std::string* error) {
- int fd = socket_loopback_server(port, type);
- if (fd < 0 && errno == EAFNOSUPPORT)
- return _fd_set_error_str(socket_loopback_server6(port, type), error);
- return _fd_set_error_str(fd, error);
-}
-
inline int network_inaddr_any_server(int port, int type, std::string* error) {
return _fd_set_error_str(socket_inaddr_any_server(port, type), error);
}
@@ -656,55 +578,6 @@
#define unix_write adb_write
#define unix_close adb_close
-// Win32 is limited to DWORDs for thread return values; limit the POSIX systems to this as well to
-// ensure compatibility.
-typedef void (*adb_thread_func_t)(void* arg);
-typedef pthread_t adb_thread_t;
-
-struct adb_pthread_args {
- adb_thread_func_t func;
- void* arg;
-};
-
-static void* adb_pthread_wrapper(void* heap_args) {
- // Move the arguments from the heap onto the thread's stack.
- adb_pthread_args thread_args = *reinterpret_cast<adb_pthread_args*>(heap_args);
- delete static_cast<adb_pthread_args*>(heap_args);
- thread_args.func(thread_args.arg);
- return nullptr;
-}
-
-static __inline__ bool adb_thread_create(adb_thread_func_t start, void* arg,
- adb_thread_t* thread = nullptr) {
- pthread_t temp;
- pthread_attr_t attr;
- pthread_attr_init(&attr);
- pthread_attr_setdetachstate(&attr, thread ? PTHREAD_CREATE_JOINABLE : PTHREAD_CREATE_DETACHED);
- auto* pthread_args = new adb_pthread_args{.func = start, .arg = arg};
- errno = pthread_create(&temp, &attr, adb_pthread_wrapper, pthread_args);
- if (errno == 0) {
- if (thread) {
- *thread = temp;
- }
- return true;
- }
- return false;
-}
-
-static __inline__ bool adb_thread_join(adb_thread_t thread) {
- errno = pthread_join(thread, nullptr);
- return errno == 0;
-}
-
-static __inline__ bool adb_thread_detach(adb_thread_t thread) {
- errno = pthread_detach(thread);
- return errno == 0;
-}
-
-static __inline__ void __attribute__((noreturn)) adb_thread_exit() {
- pthread_exit(nullptr);
-}
-
static __inline__ int adb_thread_setname(const std::string& name) {
#ifdef __APPLE__
return pthread_setname_np(name.c_str());
diff --git a/adb/sysdeps/network.h b/adb/sysdeps/network.h
new file mode 100644
index 0000000..83ce371
--- /dev/null
+++ b/adb/sysdeps/network.h
@@ -0,0 +1,22 @@
+#pragma once
+
+/*
+ * 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 <string>
+
+int network_loopback_client(int port, int type, std::string* error);
+int network_loopback_server(int port, int type, std::string* error);
diff --git a/adb/sysdeps/posix/network.cpp b/adb/sysdeps/posix/network.cpp
new file mode 100644
index 0000000..45da5af
--- /dev/null
+++ b/adb/sysdeps/posix/network.cpp
@@ -0,0 +1,127 @@
+/*
+ * 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 "sysdeps/network.h"
+
+#include <errno.h>
+#include <netinet/in.h>
+#include <sys/socket.h>
+
+#include <string>
+
+#include "adb_unique_fd.h"
+
+static void set_error(std::string* error) {
+ if (error) {
+ *error = strerror(errno);
+ }
+}
+
+static sockaddr* loopback_addr4(sockaddr_storage* addr, socklen_t* addrlen, int port) {
+ struct sockaddr_in* addr4 = reinterpret_cast<sockaddr_in*>(addr);
+ *addrlen = sizeof(*addr4);
+
+ addr4->sin_family = AF_INET;
+ addr4->sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+ addr4->sin_port = htons(port);
+ return reinterpret_cast<sockaddr*>(addr);
+}
+
+static sockaddr* loopback_addr6(sockaddr_storage* addr, socklen_t* addrlen, int port) {
+ struct sockaddr_in6* addr6 = reinterpret_cast<sockaddr_in6*>(addr);
+ *addrlen = sizeof(*addr6);
+
+ addr6->sin6_family = AF_INET6;
+ addr6->sin6_addr = in6addr_loopback;
+ addr6->sin6_port = htons(port);
+ return reinterpret_cast<sockaddr*>(addr);
+}
+
+static int _network_loopback_client(bool ipv6, int port, int type, std::string* error) {
+ unique_fd s(socket(ipv6 ? AF_INET6 : AF_INET, type, 0));
+ if (s == -1) {
+ set_error(error);
+ return -1;
+ }
+
+ struct sockaddr_storage addr_storage = {};
+ socklen_t addrlen = sizeof(addr_storage);
+ sockaddr* addr = (ipv6 ? loopback_addr6 : loopback_addr4)(&addr_storage, &addrlen, 0);
+
+ if (bind(s.get(), addr, addrlen) != 0) {
+ set_error(error);
+ return -1;
+ }
+
+ addr = (ipv6 ? loopback_addr6 : loopback_addr4)(&addr_storage, &addrlen, port);
+
+ if (connect(s.get(), addr, addrlen) != 0) {
+ set_error(error);
+ return -1;
+ }
+
+ return s.release();
+}
+
+int network_loopback_client(int port, int type, std::string* error) {
+ // Try IPv4 first, use IPv6 as a fallback.
+ int rc = _network_loopback_client(false, port, type, error);
+ if (rc == -1) {
+ return _network_loopback_client(true, port, type, error);
+ }
+ return rc;
+}
+
+static int _network_loopback_server(bool ipv6, int port, int type, std::string* error) {
+ unique_fd s(socket(ipv6 ? AF_INET6 : AF_INET, type, 0));
+ if (s == -1) {
+ set_error(error);
+ return -1;
+ }
+
+ int n = 1;
+ setsockopt(s.get(), SOL_SOCKET, SO_REUSEADDR, &n, sizeof(n));
+
+ struct sockaddr_storage addr_storage = {};
+ socklen_t addrlen = sizeof(addr_storage);
+ sockaddr* addr = (ipv6 ? loopback_addr6 : loopback_addr4)(&addr_storage, &addrlen, port);
+
+ if (bind(s, addr, addrlen) != 0) {
+ set_error(error);
+ return -1;
+ }
+
+ if (type == SOCK_STREAM || type == SOCK_SEQPACKET) {
+ // Arbitrarily selected value, ported from libcutils.
+ if (listen(s, 4) != 0) {
+ set_error(error);
+ return -1;
+ }
+ }
+
+ return s.release();
+}
+
+int network_loopback_server(int port, int type, std::string* error) {
+ int rc = _network_loopback_server(false, port, type, error);
+
+ // Only attempt to listen on IPv6 if IPv4 is unavailable.
+ // We don't want to start an IPv6 server if there's already an IPv4 one running.
+ if (rc == -1 && (errno == EADDRNOTAVAIL || errno == EAFNOSUPPORT)) {
+ return _network_loopback_server(true, port, type, error);
+ }
+ return rc;
+}
diff --git a/adb/sysdeps_test.cpp b/adb/sysdeps_test.cpp
index 9007e75..edb0fb3 100644
--- a/adb/sysdeps_test.cpp
+++ b/adb/sysdeps_test.cpp
@@ -25,54 +25,6 @@
#include "sysdeps.h"
#include "sysdeps/chrono.h"
-static void increment_atomic_int(void* c) {
- std::this_thread::sleep_for(1s);
- reinterpret_cast<std::atomic<int>*>(c)->fetch_add(1);
-}
-
-TEST(sysdeps_thread, smoke) {
- std::atomic<int> counter(0);
-
- for (int i = 0; i < 100; ++i) {
- ASSERT_TRUE(adb_thread_create(increment_atomic_int, &counter));
- }
-
- std::this_thread::sleep_for(2s);
- ASSERT_EQ(100, counter.load());
-}
-
-TEST(sysdeps_thread, join) {
- std::atomic<int> counter(0);
- std::vector<adb_thread_t> threads(500);
- for (size_t i = 0; i < threads.size(); ++i) {
- ASSERT_TRUE(adb_thread_create(increment_atomic_int, &counter, &threads[i]));
- }
-
- int current = counter.load();
- ASSERT_GE(current, 0);
- // Make sure that adb_thread_create actually creates threads, and doesn't do something silly
- // like synchronously run the function passed in. The sleep in increment_atomic_int should be
- // enough to keep this from being flakey.
- ASSERT_LT(current, 500);
-
- for (const auto& thread : threads) {
- ASSERT_TRUE(adb_thread_join(thread));
- }
-
- ASSERT_EQ(500, counter.load());
-}
-
-TEST(sysdeps_thread, exit) {
- adb_thread_t thread;
- ASSERT_TRUE(adb_thread_create(
- [](void*) {
- adb_thread_exit();
- for (;;) continue;
- },
- nullptr, &thread));
- ASSERT_TRUE(adb_thread_join(thread));
-}
-
TEST(sysdeps_socketpair, smoke) {
int fds[2];
ASSERT_EQ(0, adb_socketpair(fds)) << strerror(errno);
@@ -254,13 +206,13 @@
static std::mutex &m = *new std::mutex();
m.lock();
ASSERT_FALSE(m.try_lock());
- adb_thread_create([](void*) {
+ std::thread thread([]() {
ASSERT_FALSE(m.try_lock());
m.lock();
finished.store(true);
std::this_thread::sleep_for(200ms);
m.unlock();
- }, nullptr);
+ });
ASSERT_FALSE(finished.load());
std::this_thread::sleep_for(100ms);
@@ -270,6 +222,8 @@
m.lock();
ASSERT_TRUE(finished.load());
m.unlock();
+
+ thread.join();
}
TEST(sysdeps_mutex, recursive_mutex_smoke) {
@@ -279,12 +233,12 @@
ASSERT_TRUE(m.try_lock());
m.unlock();
- adb_thread_create([](void*) {
+ std::thread thread([]() {
ASSERT_FALSE(m.try_lock());
m.lock();
std::this_thread::sleep_for(500ms);
m.unlock();
- }, nullptr);
+ });
std::this_thread::sleep_for(100ms);
m.unlock();
@@ -292,6 +246,8 @@
ASSERT_FALSE(m.try_lock());
m.lock();
m.unlock();
+
+ thread.join();
}
TEST(sysdeps_condition_variable, smoke) {
@@ -300,14 +256,16 @@
static volatile bool flag = false;
std::unique_lock<std::mutex> lock(m);
- adb_thread_create([](void*) {
+ std::thread thread([]() {
m.lock();
flag = true;
cond.notify_one();
m.unlock();
- }, nullptr);
+ });
while (!flag) {
cond.wait(lock);
}
+
+ thread.join();
}
diff --git a/adb/transport.cpp b/adb/transport.cpp
index c951f5b..4686841 100644
--- a/adb/transport.cpp
+++ b/adb/transport.cpp
@@ -29,6 +29,7 @@
#include <algorithm>
#include <list>
#include <mutex>
+#include <thread>
#include <android-base/logging.h>
#include <android-base/parsenetaddress.h>
@@ -509,13 +510,8 @@
fdevent_set(&(t->transport_fde), FDE_READ);
- if (!adb_thread_create(write_transport_thread, t)) {
- fatal_errno("cannot create write_transport thread");
- }
-
- if (!adb_thread_create(read_transport_thread, t)) {
- fatal_errno("cannot create read_transport thread");
- }
+ std::thread(write_transport_thread, t).detach();
+ std::thread(read_transport_thread, t).detach();
}
{
diff --git a/adb/transport_local.cpp b/adb/transport_local.cpp
index 4198a52..408f51f 100644
--- a/adb/transport_local.cpp
+++ b/adb/transport_local.cpp
@@ -199,7 +199,7 @@
std::mutex &retry_ports_lock = *new std::mutex;
std::condition_variable &retry_ports_cond = *new std::condition_variable;
-static void client_socket_thread(void* x) {
+static void client_socket_thread(int) {
adb_thread_setname("client_socket_thread");
D("transport: client_socket_thread() starting");
PollAllLocalPortsForEmulator();
@@ -244,9 +244,8 @@
#else // ADB_HOST
-static void server_socket_thread(void* arg) {
+static void server_socket_thread(int port) {
int serverfd, fd;
- int port = (int) (uintptr_t) arg;
adb_thread_setname("server socket");
D("transport: server_socket_thread() starting");
@@ -325,7 +324,7 @@
* the transport registration is completed. That's why we need to send the
* 'start' request after the transport is registered.
*/
-static void qemu_socket_thread(void* arg) {
+static void qemu_socket_thread(int port) {
/* 'accept' request to the adb QEMUD service. */
static const char _accept_req[] = "accept";
/* 'start' request to the adb QEMUD service. */
@@ -333,7 +332,6 @@
/* 'ok' reply from the adb QEMUD service. */
static const char _ok_resp[] = "ok";
- const int port = (int) (uintptr_t) arg;
int fd;
char tmp[256];
char con_name[32];
@@ -350,7 +348,7 @@
/* This could be an older version of the emulator, that doesn't
* implement adb QEMUD service. Fall back to the old TCP way. */
D("adb service is not available. Falling back to TCP socket.");
- adb_thread_create(server_socket_thread, arg);
+ std::thread(server_socket_thread, port).detach();
return;
}
@@ -394,7 +392,7 @@
void local_init(int port)
{
- adb_thread_func_t func;
+ void (*func)(int);
const char* debug_name = "";
#if ADB_HOST
@@ -414,9 +412,7 @@
#endif // !ADB_HOST
D("transport: local %s init", debug_name);
- if (!adb_thread_create(func, (void *) (uintptr_t) port)) {
- fatal_errno("cannot create local socket %s thread", debug_name);
- }
+ std::thread(func, port).detach();
}
static void remote_kick(atransport *t)
diff --git a/fs_mgr/fs_mgr.cpp b/fs_mgr/fs_mgr.cpp
index a6e1344..e635e53 100644
--- a/fs_mgr/fs_mgr.cpp
+++ b/fs_mgr/fs_mgr.cpp
@@ -31,7 +31,10 @@
#include <time.h>
#include <unistd.h>
+#include <memory>
+
#include <android-base/file.h>
+#include <android-base/properties.h>
#include <android-base/stringprintf.h>
#include <android-base/unique_fd.h>
#include <cutils/android_reboot.h>
@@ -48,8 +51,10 @@
#include <logwrap/logwrap.h>
#include <private/android_logger.h> // for __android_log_is_debuggable()
+#include "fs_mgr.h"
+#include "fs_mgr_avb.h"
#include "fs_mgr_priv.h"
-#include "fs_mgr_priv_avb.h"
+#include "fs_mgr_priv_dm_ioctl.h"
#define KEY_LOC_PROP "ro.crypto.keyfile.userdata"
#define KEY_IN_FOOTER "footer"
@@ -835,7 +840,7 @@
return -1;
}
}
- if (!avb_handle->SetUpAvb(&fstab->recs[i])) {
+ if (!avb_handle->SetUpAvb(&fstab->recs[i], true /* wait_for_verity_dev */)) {
LERROR << "Failed to set up AVB on partition: "
<< fstab->recs[i].mount_point << ", skipping!";
/* Skips mounting the device. */
@@ -1047,7 +1052,7 @@
return -1;
}
}
- if (!avb_handle->SetUpAvb(&fstab->recs[i])) {
+ if (!avb_handle->SetUpAvb(&fstab->recs[i], true /* wait_for_verity_dev */)) {
LERROR << "Failed to set up AVB on partition: "
<< fstab->recs[i].mount_point << ", skipping!";
/* Skips mounting the device. */
@@ -1273,3 +1278,97 @@
return 0;
}
+
+bool fs_mgr_load_verity_state(int* mode) {
+ /* return the default mode, unless any of the verified partitions are in
+ * logging mode, in which case return that */
+ *mode = VERITY_MODE_DEFAULT;
+
+ std::unique_ptr<fstab, decltype(&fs_mgr_free_fstab)> fstab(fs_mgr_read_fstab_default(),
+ fs_mgr_free_fstab);
+ if (!fstab) {
+ LERROR << "Failed to read default fstab";
+ return false;
+ }
+
+ for (int i = 0; i < fstab->num_entries; i++) {
+ if (fs_mgr_is_avb(&fstab->recs[i])) {
+ *mode = VERITY_MODE_RESTART; // avb only supports restart mode.
+ break;
+ } else if (!fs_mgr_is_verified(&fstab->recs[i])) {
+ continue;
+ }
+
+ int current;
+ if (load_verity_state(&fstab->recs[i], ¤t) < 0) {
+ continue;
+ }
+ if (current != VERITY_MODE_DEFAULT) {
+ *mode = current;
+ break;
+ }
+ }
+
+ return true;
+}
+
+bool fs_mgr_update_verity_state(fs_mgr_verity_state_callback callback) {
+ if (!callback) {
+ return false;
+ }
+
+ int mode;
+ if (!fs_mgr_load_verity_state(&mode)) {
+ return false;
+ }
+
+ android::base::unique_fd fd(TEMP_FAILURE_RETRY(open("/dev/device-mapper", O_RDWR | O_CLOEXEC)));
+ if (fd == -1) {
+ PERROR << "Error opening device mapper";
+ return false;
+ }
+
+ std::unique_ptr<fstab, decltype(&fs_mgr_free_fstab)> fstab(fs_mgr_read_fstab_default(),
+ fs_mgr_free_fstab);
+ if (!fstab) {
+ LERROR << "Failed to read default fstab";
+ return false;
+ }
+
+ alignas(dm_ioctl) char buffer[DM_BUF_SIZE];
+ struct dm_ioctl* io = (struct dm_ioctl*)buffer;
+ bool system_root = android::base::GetProperty("ro.build.system_root_image", "") == "true";
+
+ for (int i = 0; i < fstab->num_entries; i++) {
+ if (!fs_mgr_is_verified(&fstab->recs[i]) && !fs_mgr_is_avb(&fstab->recs[i])) {
+ continue;
+ }
+
+ std::string mount_point;
+ if (system_root && !strcmp(fstab->recs[i].mount_point, "/")) {
+ mount_point = "system";
+ } else {
+ mount_point = basename(fstab->recs[i].mount_point);
+ }
+
+ fs_mgr_verity_ioctl_init(io, mount_point, 0);
+
+ const char* status;
+ if (ioctl(fd, DM_TABLE_STATUS, io)) {
+ if (fstab->recs[i].fs_mgr_flags & MF_VERIFYATBOOT) {
+ status = "V";
+ } else {
+ PERROR << "Failed to query DM_TABLE_STATUS for " << mount_point.c_str();
+ continue;
+ }
+ }
+
+ status = &buffer[io->data_start + sizeof(struct dm_target_spec)];
+
+ if (*status == 'C' || *status == 'V') {
+ callback(&fstab->recs[i], mount_point.c_str(), mode, *status);
+ }
+ }
+
+ return true;
+}
diff --git a/fs_mgr/fs_mgr_avb.cpp b/fs_mgr/fs_mgr_avb.cpp
index 76ec236..7c82bb1 100644
--- a/fs_mgr/fs_mgr_avb.cpp
+++ b/fs_mgr/fs_mgr_avb.cpp
@@ -38,9 +38,9 @@
#include <utils/Compat.h>
#include "fs_mgr.h"
+#include "fs_mgr_avb.h"
#include "fs_mgr_avb_ops.h"
#include "fs_mgr_priv.h"
-#include "fs_mgr_priv_avb.h"
#include "fs_mgr_priv_dm_ioctl.h"
#include "fs_mgr_priv_sha.h"
@@ -336,7 +336,8 @@
static bool hashtree_dm_verity_setup(struct fstab_rec* fstab_entry,
const AvbHashtreeDescriptor& hashtree_desc,
- const std::string& salt, const std::string& root_digest) {
+ const std::string& salt, const std::string& root_digest,
+ bool wait_for_verity_dev) {
// Gets the device mapper fd.
android::base::unique_fd fd(open("/dev/device-mapper", O_RDWR));
if (fd < 0) {
@@ -375,13 +376,12 @@
// Marks the underlying block device as read-only.
fs_mgr_set_blk_ro(fstab_entry->blk_device);
- // TODO(bowgotsai): support verified all partition at boot.
// Updates fstab_rec->blk_device to verity device name.
free(fstab_entry->blk_device);
fstab_entry->blk_device = strdup(verity_blk_name.c_str());
// Makes sure we've set everything up properly.
- if (fs_mgr_test_access(verity_blk_name.c_str()) < 0) {
+ if (wait_for_verity_dev && fs_mgr_test_access(verity_blk_name.c_str()) < 0) {
return false;
}
@@ -519,7 +519,7 @@
return nullptr;
}
-bool FsManagerAvbHandle::SetUpAvb(struct fstab_rec* fstab_entry) {
+bool FsManagerAvbHandle::SetUpAvb(struct fstab_rec* fstab_entry, bool wait_for_verity_dev) {
if (!fstab_entry) return false;
if (!avb_slot_data_ || avb_slot_data_->num_vbmeta_images < 1) {
return false;
@@ -545,7 +545,8 @@
}
// Converts HASHTREE descriptor to verity_table_params.
- if (!hashtree_dm_verity_setup(fstab_entry, hashtree_descriptor, salt, root_digest)) {
+ if (!hashtree_dm_verity_setup(fstab_entry, hashtree_descriptor, salt, root_digest,
+ wait_for_verity_dev)) {
return false;
}
return true;
diff --git a/fs_mgr/fs_mgr_fstab.cpp b/fs_mgr/fs_mgr_fstab.cpp
index dfbde18..dc73c24 100644
--- a/fs_mgr/fs_mgr_fstab.cpp
+++ b/fs_mgr/fs_mgr_fstab.cpp
@@ -768,6 +768,11 @@
return fstab->fs_mgr_flags & MF_VERIFY;
}
+int fs_mgr_is_avb(const struct fstab_rec *fstab)
+{
+ return fstab->fs_mgr_flags & MF_AVB;
+}
+
int fs_mgr_is_verifyatboot(const struct fstab_rec *fstab)
{
return fstab->fs_mgr_flags & MF_VERIFYATBOOT;
diff --git a/fs_mgr/fs_mgr_priv.h b/fs_mgr/fs_mgr_priv.h
index dedffd8..c985462 100644
--- a/fs_mgr/fs_mgr_priv.h
+++ b/fs_mgr/fs_mgr_priv.h
@@ -115,5 +115,6 @@
bool fs_mgr_update_for_slotselect(struct fstab *fstab);
bool is_dt_compatible();
bool is_device_secure();
+int load_verity_state(struct fstab_rec* fstab, int* mode);
#endif /* __CORE_FS_MGR_PRIV_H */
diff --git a/fs_mgr/fs_mgr_verity.cpp b/fs_mgr/fs_mgr_verity.cpp
index 8c7a8ca..0bf173b 100644
--- a/fs_mgr/fs_mgr_verity.cpp
+++ b/fs_mgr/fs_mgr_verity.cpp
@@ -653,8 +653,7 @@
offset);
}
-static int load_verity_state(struct fstab_rec *fstab, int *mode)
-{
+int load_verity_state(struct fstab_rec* fstab, int* mode) {
int match = 0;
off64_t offset = 0;
@@ -690,129 +689,6 @@
return read_verity_state(fstab->verity_loc, offset, mode);
}
-int fs_mgr_load_verity_state(int *mode)
-{
- int rc = -1;
- int i;
- int current;
- struct fstab *fstab = NULL;
-
- /* return the default mode, unless any of the verified partitions are in
- * logging mode, in which case return that */
- *mode = VERITY_MODE_DEFAULT;
-
- fstab = fs_mgr_read_fstab_default();
- if (!fstab) {
- LERROR << "Failed to read default fstab";
- goto out;
- }
-
- for (i = 0; i < fstab->num_entries; i++) {
- if (!fs_mgr_is_verified(&fstab->recs[i])) {
- continue;
- }
-
- rc = load_verity_state(&fstab->recs[i], ¤t);
- if (rc < 0) {
- continue;
- }
-
- if (current != VERITY_MODE_DEFAULT) {
- *mode = current;
- break;
- }
- }
-
- rc = 0;
-
-out:
- if (fstab) {
- fs_mgr_free_fstab(fstab);
- }
-
- return rc;
-}
-
-int fs_mgr_update_verity_state(fs_mgr_verity_state_callback callback)
-{
- alignas(dm_ioctl) char buffer[DM_BUF_SIZE];
- bool system_root = false;
- std::string mount_point;
- char propbuf[PROPERTY_VALUE_MAX];
- const char *status;
- int fd = -1;
- int i;
- int mode;
- int rc = -1;
- struct dm_ioctl *io = (struct dm_ioctl *) buffer;
- struct fstab *fstab = NULL;
-
- if (!callback) {
- return -1;
- }
-
- if (fs_mgr_load_verity_state(&mode) == -1) {
- return -1;
- }
-
- 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.build.system_root_image", propbuf, "");
- system_root = !strcmp(propbuf, "true");
- fstab = fs_mgr_read_fstab_default();
- if (!fstab) {
- LERROR << "Failed to read default fstab";
- goto out;
- }
-
- for (i = 0; i < fstab->num_entries; i++) {
- if (!fs_mgr_is_verified(&fstab->recs[i])) {
- continue;
- }
-
- if (system_root && !strcmp(fstab->recs[i].mount_point, "/")) {
- mount_point = "system";
- } else {
- mount_point = basename(fstab->recs[i].mount_point);
- }
-
- fs_mgr_verity_ioctl_init(io, mount_point, 0);
-
- if (ioctl(fd, DM_TABLE_STATUS, io)) {
- if (fstab->recs[i].fs_mgr_flags & MF_VERIFYATBOOT) {
- status = "V";
- } else {
- PERROR << "Failed to query DM_TABLE_STATUS for "
- << mount_point.c_str();
- continue;
- }
- }
-
- status = &buffer[io->data_start + sizeof(struct dm_target_spec)];
-
- if (*status == 'C' || *status == 'V') {
- callback(&fstab->recs[i], mount_point.c_str(), mode, *status);
- }
- }
-
- rc = 0;
-
-out:
- if (fstab) {
- fs_mgr_free_fstab(fstab);
- }
-
- if (fd) {
- close(fd);
- }
-
- return rc;
-}
-
static void update_verity_table_blk_device(char *blk_device, char **table)
{
std::string result, word;
diff --git a/fs_mgr/include/fs_mgr.h b/fs_mgr/include/fs_mgr.h
index 3c2fea4..12db672 100644
--- a/fs_mgr/include/fs_mgr.h
+++ b/fs_mgr/include/fs_mgr.h
@@ -113,8 +113,8 @@
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);
-int fs_mgr_load_verity_state(int *mode);
-int fs_mgr_update_verity_state(fs_mgr_verity_state_callback callback);
+bool fs_mgr_load_verity_state(int* mode);
+bool fs_mgr_update_verity_state(fs_mgr_verity_state_callback callback);
int fs_mgr_add_entry(struct fstab *fstab,
const char *mount_point, const char *fs_type,
const char *blk_device);
@@ -123,6 +123,7 @@
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_avb(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);
diff --git a/fs_mgr/fs_mgr_priv_avb.h b/fs_mgr/include/fs_mgr_avb.h
similarity index 83%
rename from fs_mgr/fs_mgr_priv_avb.h
rename to fs_mgr/include/fs_mgr_avb.h
index 99a033e..526a5ce 100644
--- a/fs_mgr/fs_mgr_priv_avb.h
+++ b/fs_mgr/include/fs_mgr_avb.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2016 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,8 +14,8 @@
* limitations under the License.
*/
-#ifndef __CORE_FS_MGR_PRIV_AVB_H
-#define __CORE_FS_MGR_PRIV_AVB_H
+#ifndef __CORE_FS_MGR_AVB_H
+#define __CORE_FS_MGR_AVB_H
#include <memory>
#include <string>
@@ -63,18 +63,22 @@
static FsManagerAvbUniquePtr Open(const std::string& device_file_by_name_prefix);
// Sets up dm-verity on the given fstab entry.
+ // The 'wait_for_verity_dev' parameter makes this function wait for the
+ // verity device to get created before return.
// Returns true if the mount point is eligible to mount, it includes:
// - status_ is kFsMgrAvbHandleHashtreeDisabled or
// - status_ is kFsMgrAvbHandleSuccess and sending ioctl DM_TABLE_LOAD
// to load verity table is success.
// Otherwise, returns false.
- bool SetUpAvb(fstab_rec* fstab_entry);
+ bool SetUpAvb(fstab_rec* fstab_entry, bool wait_for_verity_dev);
- FsManagerAvbHandle(const FsManagerAvbHandle&) = delete; // no copy
- FsManagerAvbHandle& operator=(const FsManagerAvbHandle&) = delete; // no assignment
+ bool AvbHashtreeDisabled() { return status_ == kFsManagerAvbHandleHashtreeDisabled; }
- FsManagerAvbHandle(FsManagerAvbHandle&&) noexcept = delete; // no move
- FsManagerAvbHandle& operator=(FsManagerAvbHandle&&) noexcept = delete; // no move assignment
+ FsManagerAvbHandle(const FsManagerAvbHandle&) = delete; // no copy
+ FsManagerAvbHandle& operator=(const FsManagerAvbHandle&) = delete; // no assignment
+
+ FsManagerAvbHandle(FsManagerAvbHandle&&) noexcept = delete; // no move
+ FsManagerAvbHandle& operator=(FsManagerAvbHandle&&) noexcept = delete; // no move assignment
~FsManagerAvbHandle() {
if (avb_slot_data_) {
@@ -90,4 +94,4 @@
FsManagerAvbHandleStatus status_;
};
-#endif /* __CORE_FS_MGR_PRIV_AVB_H */
+#endif /* __CORE_FS_MGR_AVB_H */
diff --git a/init/Android.mk b/init/Android.mk
index 7e9b613..f2c0842 100644
--- a/init/Android.mk
+++ b/init/Android.mk
@@ -74,7 +74,7 @@
service.cpp \
util.cpp \
-LOCAL_STATIC_LIBRARIES := libbase libselinux liblog libprocessgroup libnl
+LOCAL_STATIC_LIBRARIES := libbase libselinux liblog libprocessgroup
LOCAL_WHOLE_STATIC_LIBRARIES := libcap
LOCAL_MODULE := libinit
LOCAL_SANITIZE := integer
@@ -111,8 +111,8 @@
libfec_rs \
libsquashfs_utils \
liblogwrap \
- libcutils \
libext4_utils \
+ libcutils \
libbase \
libc \
libselinux \
@@ -124,7 +124,6 @@
libsparse \
libz \
libprocessgroup \
- libnl \
libavb
# Create symlinks.
diff --git a/init/builtins.cpp b/init/builtins.cpp
index e1d9b94..2327cdf 100644
--- a/init/builtins.cpp
+++ b/init/builtins.cpp
@@ -677,11 +677,11 @@
static int do_verity_load_state(const std::vector<std::string>& args) {
int mode = -1;
- int rc = fs_mgr_load_verity_state(&mode);
- if (rc == 0 && mode != VERITY_MODE_DEFAULT) {
+ bool loaded = fs_mgr_load_verity_state(&mode);
+ if (loaded && mode != VERITY_MODE_DEFAULT) {
ActionManager::GetInstance().QueueEventTrigger("verity-logging");
}
- return rc;
+ return loaded ? 0 : 1;
}
static void verity_update_property(fstab_rec *fstab, const char *mount_point,
@@ -691,7 +691,7 @@
}
static int do_verity_update_state(const std::vector<std::string>& args) {
- return fs_mgr_update_verity_state(verity_update_property);
+ return fs_mgr_update_verity_state(verity_update_property) ? 0 : 1;
}
static int do_write(const std::vector<std::string>& args) {
diff --git a/init/devices.cpp b/init/devices.cpp
index 6cd3564..ad313a0 100644
--- a/init/devices.cpp
+++ b/init/devices.cpp
@@ -56,9 +56,6 @@
#include "util.h"
#define SYSFS_PREFIX "/sys"
-static const char *firmware_dirs[] = { "/etc/firmware",
- "/vendor/firmware",
- "/firmware/image" };
extern struct selabel_handle *sehandle;
@@ -79,16 +76,8 @@
struct listnode plist;
};
-struct platform_node {
- char *name;
- char *path;
- int path_len;
- struct listnode list;
-};
-
static list_declare(sys_perms);
static list_declare(dev_perms);
-static list_declare(platform_names);
int add_dev_perms(const char *name, const char *attr,
mode_t perm, unsigned int uid, unsigned int gid,
@@ -153,17 +142,18 @@
return perm_path_matches(subsys_path.c_str(), dp);
}
-static void fixup_sys_perms(const char* upath, const char* subsystem) {
+static void fixup_sys_perms(const std::string& upath, const std::string& subsystem) {
// upaths omit the "/sys" that paths in this list
// contain, so we prepend it...
- std::string path = std::string(SYSFS_PREFIX) + upath;
+ std::string path = SYSFS_PREFIX + upath;
listnode* node;
list_for_each(node, &sys_perms) {
perms_* dp = &(node_to_item(node, perm_node, plist))->dp;
- if (match_subsystem(dp, SYSFS_PREFIX "/class/%s/%s", path.c_str(), subsystem)) {
+ if (match_subsystem(dp, SYSFS_PREFIX "/class/%s/%s", path.c_str(), subsystem.c_str())) {
; // matched
- } else if (match_subsystem(dp, SYSFS_PREFIX "/bus/%s/devices/%s", path.c_str(), subsystem)) {
+ } else if (match_subsystem(dp, SYSFS_PREFIX "/bus/%s/devices/%s", path.c_str(),
+ subsystem.c_str())) {
; // matched
} else if (!perm_path_matches(path.c_str(), dp)) {
continue;
@@ -209,7 +199,7 @@
return 0600;
}
-static void make_device(const char* path, const char* /*upath*/, int block, int major, int minor,
+static void make_device(const std::string& path, int block, int major, int minor,
const std::vector<std::string>& links) {
unsigned uid;
unsigned gid;
@@ -217,7 +207,7 @@
dev_t dev;
char *secontext = NULL;
- mode = get_device_perm(path, links, &uid, &gid) | (block ? S_IFBLK : S_IFCHR);
+ mode = get_device_perm(path.c_str(), links, &uid, &gid) | (block ? S_IFBLK : S_IFCHR);
if (sehandle) {
std::vector<const char*> c_links;
@@ -225,7 +215,7 @@
c_links.emplace_back(link.c_str());
}
c_links.emplace_back(nullptr);
- if (selabel_lookup_best_match(sehandle, &secontext, path, &c_links[0], mode)) {
+ if (selabel_lookup_best_match(sehandle, &secontext, path.c_str(), &c_links[0], mode)) {
PLOG(ERROR) << "Device '" << path << "' not created; cannot find SELinux label";
return;
}
@@ -244,10 +234,9 @@
}
/* 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) {
-
+ if (mknod(path.c_str(), mode, dev) && (errno == EEXIST) && secontext) {
char* fcon = nullptr;
- int rc = lgetfilecon(path, &fcon);
+ int rc = lgetfilecon(path.c_str(), &fcon);
if (rc < 0) {
PLOG(ERROR) << "Cannot get SELinux label on '" << path << "' device";
goto out;
@@ -256,13 +245,13 @@
bool different = strcmp(fcon, secontext) != 0;
freecon(fcon);
- if (different && lsetfilecon(path, secontext)) {
+ if (different && lsetfilecon(path.c_str(), secontext)) {
PLOG(ERROR) << "Cannot set '" << secontext << "' SELinux label on '" << path << "' device";
}
}
out:
- chown(path, uid, -1);
+ chown(path.c_str(), uid, -1);
if (setegid(AID_ROOT)) {
PLOG(FATAL) << "setegid(AID_ROOT) failed";
}
@@ -273,75 +262,25 @@
}
}
-void add_platform_device(const char* path) {
- int path_len = strlen(path);
- struct platform_node *bus;
- const char *name = path;
+// TODO: Move this to be a member variable of a future devices class.
+std::vector<std::string> platform_devices;
- if (!strncmp(path, "/devices/", 9)) {
- name += 9;
- if (!strncmp(name, "platform/", 9))
- name += 9;
- }
-
- LOG(VERBOSE) << "adding platform device " << name << " (" << path << ")";
-
- bus = (platform_node*) calloc(1, sizeof(struct platform_node));
- bus->path = strdup(path);
- bus->path_len = path_len;
- bus->name = bus->path + (name - path);
- list_add_tail(&platform_names, &bus->list);
-}
-
-/*
- * given a path that may start with a platform device, find the length of the
- * platform device prefix. If it doesn't start with a platform device, return
- * 0.
- */
-static struct platform_node *find_platform_device(const char *path)
-{
- int path_len = strlen(path);
- struct listnode *node;
- struct platform_node *bus;
-
- list_for_each_reverse(node, &platform_names) {
- bus = node_to_item(node, struct platform_node, list);
- if ((bus->path_len < path_len) &&
- (path[bus->path_len] == '/') &&
- !strncmp(path, bus->path, bus->path_len))
- return bus;
- }
-
- return NULL;
-}
-
-void remove_platform_device(const char* path) {
- struct listnode *node;
- struct platform_node *bus;
-
- list_for_each_reverse(node, &platform_names) {
- bus = node_to_item(node, struct platform_node, list);
- if (!strcmp(path, bus->path)) {
- LOG(INFO) << "removing platform device " << bus->name;
- free(bus->path);
- list_remove(node);
- free(bus);
- return;
+// Given a path that may start with a platform device, find the length of the
+// platform device prefix. If it doesn't start with a platform device, return false
+bool find_platform_device(const std::string& path, std::string* out_path) {
+ out_path->clear();
+ // platform_devices is searched backwards, since parents are added before their children,
+ // and we want to match as deep of a child as we can.
+ for (auto it = platform_devices.rbegin(); it != platform_devices.rend(); ++it) {
+ auto platform_device_path_length = it->length();
+ if (platform_device_path_length < path.length() &&
+ path[platform_device_path_length] == '/' &&
+ android::base::StartsWith(path, it->c_str())) {
+ *out_path = *it;
+ return true;
}
}
-}
-
-static void destroy_platform_devices() {
- struct listnode* node;
- struct listnode* n;
- struct platform_node* bus;
-
- list_for_each_safe(node, n, &platform_names) {
- list_remove(node);
- bus = node_to_item(node, struct platform_node, list);
- free(bus->path);
- free(bus);
- }
+ return false;
}
/* Given a path that may start with a PCI device, populate the supplied buffer
@@ -398,19 +337,11 @@
return true;
}
-static void parse_event(const char *msg, struct uevent *uevent)
-{
- uevent->action = "";
- uevent->path = "";
- uevent->subsystem = "";
- uevent->firmware = "";
+void parse_event(const char* msg, uevent* uevent) {
+ uevent->partition_num = -1;
uevent->major = -1;
uevent->minor = -1;
- uevent->partition_name = NULL;
- uevent->partition_num = -1;
- uevent->device_name = NULL;
-
- /* currently ignoring SEQNUM */
+ // currently ignoring SEQNUM
while(*msg) {
if(!strncmp(msg, "ACTION=", 7)) {
msg += 7;
@@ -441,30 +372,26 @@
uevent->device_name = msg;
}
- /* advance to after the next \0 */
+ // advance to after the next \0
while(*msg++)
;
}
if (LOG_UEVENTS) {
- LOG(INFO) << android::base::StringPrintf("event { '%s', '%s', '%s', '%s', %d, %d }",
- uevent->action, uevent->path, uevent->subsystem,
- uevent->firmware, uevent->major, uevent->minor);
+ LOG(INFO) << "event { '" << uevent->action << "', '" << uevent->path << "', '"
+ << uevent->subsystem << "', '" << uevent->firmware << "', " << uevent->major
+ << ", " << uevent->minor << " }";
}
}
std::vector<std::string> get_character_device_symlinks(uevent* uevent) {
- platform_node* pdev = find_platform_device(uevent->path);
- if (!pdev) return {};
+ std::string parent_device;
+ if (!find_platform_device(uevent->path, &parent_device)) return {};
- /* skip "/devices/platform/<driver>" */
- std::string parent = std::string(uevent->path);
- auto parent_start = parent.find('/', pdev->path_len);
- if (parent_start == std::string::npos) return {};
+ // skip path to the parent driver
+ std::string path = uevent->path.substr(parent_device.length());
- parent.erase(0, parent_start);
-
- if (!android::base::StartsWith(parent, "/usb")) return {};
+ if (!android::base::StartsWith(path, "/usb")) return {};
// skip root hub name and device. use device interface
// skip 3 slashes, including the first / by starting the search at the 1st character, not 0th.
@@ -472,13 +399,13 @@
// e.g. "/usb/usb_device/name/tty2-1:1.0" -> "name"
std::string::size_type start = 0;
- start = parent.find('/', start + 1);
+ start = path.find('/', start + 1);
if (start == std::string::npos) return {};
- start = parent.find('/', start + 1);
+ start = path.find('/', start + 1);
if (start == std::string::npos) return {};
- auto end = parent.find('/', start + 1);
+ auto end = path.find('/', start + 1);
if (end == std::string::npos) return {};
start++; // Skip the first '/'
@@ -486,11 +413,10 @@
auto length = end - start;
if (length == 0) return {};
- auto name_string = parent.substr(start, length);
+ auto name_string = path.substr(start, length);
- // TODO: remove std::string() when uevent->subsystem is an std::string
std::vector<std::string> links;
- links.emplace_back("/dev/usb/" + std::string(uevent->subsystem) + name_string);
+ links.emplace_back("/dev/usb/" + uevent->subsystem + name_string);
mkdir("/dev/usb", 0755);
@@ -516,12 +442,19 @@
std::vector<std::string> get_block_device_symlinks(uevent* uevent) {
std::string device;
- struct platform_node* pdev;
std::string type;
- pdev = find_platform_device(uevent->path);
- if (pdev) {
- device = pdev->name;
+ if (find_platform_device(uevent->path, &device)) {
+ // Skip /devices/platform or /devices/ if present
+ static const std::string devices_platform_prefix = "/devices/platform/";
+ static const std::string devices_prefix = "/devices/";
+
+ if (android::base::StartsWith(device, devices_platform_prefix.c_str())) {
+ device = device.substr(devices_platform_prefix.length());
+ } else if (android::base::StartsWith(device, devices_prefix.c_str())) {
+ device = device.substr(devices_prefix.length());
+ }
+
type = "platform";
} else if (find_pci_device_prefix(uevent->path, &device)) {
type = "pci";
@@ -537,7 +470,7 @@
auto link_path = "/dev/block/" + type + "/" + device;
- if (uevent->partition_name) {
+ if (!uevent->partition_name.empty()) {
std::string partition_name_sanitized(uevent->partition_name);
sanitize_partition_name(&partition_name_sanitized);
if (partition_name_sanitized != uevent->partition_name) {
@@ -551,57 +484,51 @@
links.emplace_back(link_path + "/by-num/p" + std::to_string(uevent->partition_num));
}
- // TODO: remove uevent_path when uevent->path is an std::string
- std::string uevent_path = uevent->path;
- auto last_slash = uevent_path.rfind('/');
- links.emplace_back(link_path + "/" + uevent_path.substr(last_slash + 1));
+ auto last_slash = uevent->path.rfind('/');
+ links.emplace_back(link_path + "/" + uevent->path.substr(last_slash + 1));
return links;
}
-static void make_link_init(const char* oldpath, const char* newpath) {
- const char* slash = strrchr(newpath, '/');
- if (!slash) return;
+static void make_link_init(const std::string& oldpath, const std::string& newpath) {
+ if (mkdir_recursive(dirname(newpath.c_str()), 0755)) {
+ PLOG(ERROR) << "Failed to create directory " << dirname(newpath.c_str());
+ }
- if (mkdir_recursive(dirname(newpath), 0755)) {
- PLOG(ERROR) << "Failed to create directory " << dirname(newpath);
- }
-
- if (symlink(oldpath, newpath) && errno != EEXIST) {
- PLOG(ERROR) << "Failed to symlink " << oldpath << " to " << newpath;
- }
+ if (symlink(oldpath.c_str(), newpath.c_str()) && errno != EEXIST) {
+ PLOG(ERROR) << "Failed to symlink " << oldpath << " to " << newpath;
+ }
}
-static void remove_link(const char* oldpath, const char* newpath) {
- std::string path;
- if (android::base::Readlink(newpath, &path) && path == oldpath) unlink(newpath);
+static void remove_link(const std::string& oldpath, const std::string& newpath) {
+ std::string path;
+ if (android::base::Readlink(newpath, &path) && path == oldpath) unlink(newpath.c_str());
}
-static void handle_device(const char* action, const char* devpath, const char* path, int block,
+static void handle_device(const std::string& action, const std::string& devpath, int block,
int major, int minor, const std::vector<std::string>& links) {
- if(!strcmp(action, "add")) {
- make_device(devpath, path, block, major, minor, links);
+ if (action == "add") {
+ make_device(devpath, block, major, minor, links);
for (const auto& link : links) {
- make_link_init(devpath, link.c_str());
+ make_link_init(devpath, link);
}
}
- if(!strcmp(action, "remove")) {
+ if (action == "remove") {
for (const auto& link : links) {
- remove_link(devpath, link.c_str());
+ remove_link(devpath, link);
}
- unlink(devpath);
+ unlink(devpath.c_str());
}
}
-static void handle_platform_device_event(struct uevent *uevent)
-{
- const char *path = uevent->path;
-
- if (!strcmp(uevent->action, "add"))
- add_platform_device(path);
- else if (!strcmp(uevent->action, "remove"))
- remove_platform_device(path);
+void handle_platform_device_event(uevent* uevent) {
+ if (uevent->action == "add") {
+ platform_devices.emplace_back(uevent->path);
+ } else if (uevent->action == "remove") {
+ auto it = std::find(platform_devices.begin(), platform_devices.end(), uevent->path);
+ if (it != platform_devices.end()) platform_devices.erase(it);
+ }
}
static void handle_block_device_event(uevent* uevent) {
@@ -615,11 +542,11 @@
std::string devpath = base + name;
std::vector<std::string> links;
- if (!strncmp(uevent->path, "/devices/", 9))
+ if (android::base::StartsWith(uevent->path, "/devices")) {
links = get_block_device_symlinks(uevent);
+ }
- handle_device(uevent->action, devpath.c_str(), uevent->path, 1, uevent->major, uevent->minor,
- links);
+ handle_device(uevent->action, devpath, 1, uevent->major, uevent->minor, links);
}
static void handle_generic_device_event(uevent* uevent) {
@@ -627,7 +554,7 @@
if (uevent->major < 0 || uevent->minor < 0) return;
std::string name = android::base::Basename(uevent->path);
- ueventd_subsystem* subsystem = ueventd_subsystem_find_by_name(uevent->subsystem);
+ ueventd_subsystem* subsystem = ueventd_subsystem_find_by_name(uevent->subsystem.c_str());
std::string devpath;
@@ -651,11 +578,10 @@
// TODO: Remove std::string()
devpath = std::string(subsystem->dirname) + "/" + devname;
mkdir_recursive(android::base::Dirname(devpath), 0755);
- } else if (!strncmp(uevent->subsystem, "usb", 3)) {
- if (!strcmp(uevent->subsystem, "usb")) {
- if (uevent->device_name) {
- // TODO: Remove std::string
- devpath = "/dev/" + std::string(uevent->device_name);
+ } else if (android::base::StartsWith(uevent->subsystem, "usb")) {
+ if (uevent->subsystem == "usb") {
+ if (!uevent->device_name.empty()) {
+ devpath = "/dev/" + uevent->device_name;
} else {
// This imitates the file system that would be created
// if we were using devfs instead.
@@ -675,18 +601,18 @@
auto links = get_character_device_symlinks(uevent);
- handle_device(uevent->action, devpath.c_str(), uevent->path, 0, uevent->major, uevent->minor,
- links);
+ handle_device(uevent->action, devpath, 0, uevent->major, uevent->minor, links);
}
static void handle_device_event(struct uevent *uevent)
{
- if (!strcmp(uevent->action,"add") || !strcmp(uevent->action, "change") || !strcmp(uevent->action, "online"))
+ if (uevent->action == "add" || uevent->action == "change" || uevent->action == "online") {
fixup_sys_perms(uevent->path, uevent->subsystem);
+ }
- if (!strncmp(uevent->subsystem, "block", 5)) {
+ if (uevent->subsystem == "block") {
handle_block_device_event(uevent);
- } else if (!strncmp(uevent->subsystem, "platform", 8)) {
+ } else if (uevent->subsystem == "platform") {
handle_platform_device_event(uevent);
} else {
handle_generic_device_event(uevent);
@@ -719,7 +645,7 @@
LOG(INFO) << "firmware: loading '" << uevent->firmware << "' for '" << uevent->path << "'";
- std::string root = android::base::StringPrintf("/sys%s", uevent->path);
+ std::string root = "/sys" + uevent->path;
std::string loading = root + "/loading";
std::string data = root + "/data";
@@ -735,9 +661,12 @@
return;
}
+ static const char* firmware_dirs[] = {"/etc/firmware/", "/vendor/firmware/",
+ "/firmware/image/"};
+
try_loading_again:
for (size_t i = 0; i < arraysize(firmware_dirs); i++) {
- std::string file = android::base::StringPrintf("%s/%s", firmware_dirs[i], uevent->firmware);
+ std::string file = firmware_dirs[i] + uevent->firmware;
android::base::unique_fd fw_fd(open(file.c_str(), O_RDONLY|O_CLOEXEC));
struct stat sb;
if (fw_fd != -1 && fstat(fw_fd, &sb) != -1) {
@@ -761,8 +690,7 @@
}
static void handle_firmware_event(uevent* uevent) {
- if (strcmp(uevent->subsystem, "firmware")) return;
- if (strcmp(uevent->action, "add")) return;
+ if (uevent->subsystem != "firmware" || uevent->action != "add") return;
// Loading the firmware in a child means we can do that in parallel...
// (We ignore SIGCHLD rather than wait for our children.)
@@ -796,7 +724,7 @@
msg[n] = '\0';
msg[n+1] = '\0';
- struct uevent uevent;
+ uevent uevent;
parse_event(msg, &uevent);
coldboot_action_t act = handle_uevent(&uevent);
if (should_stop_coldboot(act))
@@ -940,7 +868,7 @@
}
void device_close() {
- destroy_platform_devices();
+ platform_devices.clear();
device_fd.reset();
selinux_status_close();
}
diff --git a/init/devices.h b/init/devices.h
index f6183c9..b8b039f 100644
--- a/init/devices.h
+++ b/init/devices.h
@@ -36,12 +36,12 @@
};
struct uevent {
- const char* action;
- const char* path;
- const char* subsystem;
- const char* firmware;
- const char* partition_name;
- const char* device_name;
+ std::string action;
+ std::string path;
+ std::string subsystem;
+ std::string firmware;
+ std::string partition_name;
+ std::string device_name;
int partition_num;
int major;
int minor;
@@ -59,10 +59,11 @@
int get_device_fd();
// Exposed for testing
-void add_platform_device(const char* path);
-void remove_platform_device(const char* path);
+extern std::vector<std::string> platform_devices;
+bool find_platform_device(const std::string& path, std::string* out_path);
std::vector<std::string> get_character_device_symlinks(uevent* uevent);
std::vector<std::string> get_block_device_symlinks(uevent* uevent);
void sanitize_partition_name(std::string* string);
+void handle_platform_device_event(uevent* uevent);
#endif /* _INIT_DEVICES_H */
diff --git a/init/devices_test.cpp b/init/devices_test.cpp
index 5be0d88..693fb54 100644
--- a/init/devices_test.cpp
+++ b/init/devices_test.cpp
@@ -22,12 +22,26 @@
#include <android-base/scopeguard.h>
#include <gtest/gtest.h>
+void add_platform_device(const std::string& path) {
+ uevent uevent = {
+ .action = "add", .subsystem = "platform", .path = path,
+ };
+ handle_platform_device_event(&uevent);
+}
+
+void remove_platform_device(const std::string& path) {
+ uevent uevent = {
+ .action = "remove", .subsystem = "platform", .path = path,
+ };
+ handle_platform_device_event(&uevent);
+}
+
template <std::vector<std::string> (*Function)(uevent*)>
void test_get_symlinks(const std::string& platform_device_name, uevent* uevent,
const std::vector<std::string> expected_links) {
- add_platform_device(platform_device_name.c_str());
+ add_platform_device(platform_device_name);
auto platform_device_remover = android::base::make_scope_guard(
- [&platform_device_name]() { remove_platform_device(platform_device_name.c_str()); });
+ [&platform_device_name]() { remove_platform_device(platform_device_name); });
std::vector<std::string> result = Function(uevent);
@@ -41,6 +55,36 @@
}
}
+TEST(devices, handle_platform_device_event) {
+ platform_devices.clear();
+ add_platform_device("/devices/platform/some_device_name");
+ ASSERT_EQ(1U, platform_devices.size());
+ remove_platform_device("/devices/platform/some_device_name");
+ ASSERT_EQ(0U, platform_devices.size());
+}
+
+TEST(devices, find_platform_device) {
+ platform_devices.clear();
+ add_platform_device("/devices/platform/some_device_name");
+ add_platform_device("/devices/platform/some_device_name/longer");
+ add_platform_device("/devices/platform/other_device_name");
+ EXPECT_EQ(3U, platform_devices.size());
+
+ std::string out_path;
+ EXPECT_FALSE(find_platform_device("/devices/platform/not_found", &out_path));
+ EXPECT_EQ("", out_path);
+
+ EXPECT_FALSE(
+ find_platform_device("/devices/platform/some_device_name_with_same_prefix", &out_path));
+
+ EXPECT_TRUE(
+ find_platform_device("/devices/platform/some_device_name/longer/longer_child", &out_path));
+ EXPECT_EQ("/devices/platform/some_device_name/longer", out_path);
+
+ EXPECT_TRUE(find_platform_device("/devices/platform/some_device_name/other_child", &out_path));
+ EXPECT_EQ("/devices/platform/some_device_name", out_path);
+}
+
TEST(devices, get_character_device_symlinks_success) {
const char* platform_device = "/devices/platform/some_device_name";
uevent uevent = {
@@ -127,7 +171,7 @@
const char* platform_device = "/devices/soc.0/f9824900.sdhci";
uevent uevent = {
.path = "/devices/soc.0/f9824900.sdhci/mmc_host/mmc0/mmc0:0001/block/mmcblk0",
- .partition_name = nullptr,
+ .partition_name = "",
.partition_num = -1,
};
std::vector<std::string> expected_result{"/dev/block/platform/soc.0/f9824900.sdhci/mmcblk0"};
@@ -156,7 +200,7 @@
const char* platform_device = "/devices/soc.0/f9824900.sdhci";
uevent uevent = {
.path = "/devices/soc.0/f9824900.sdhci/mmc_host/mmc0/mmc0:0001/block/mmcblk0p1",
- .partition_name = nullptr,
+ .partition_name = "",
.partition_num = 1,
};
std::vector<std::string> expected_result{
@@ -185,9 +229,7 @@
TEST(devices, get_block_device_symlinks_success_pci) {
const char* platform_device = "/devices/do/not/match";
uevent uevent = {
- .path = "/devices/pci0000:00/0000:00:1f.2/mmcblk0",
- .partition_name = nullptr,
- .partition_num = -1,
+ .path = "/devices/pci0000:00/0000:00:1f.2/mmcblk0", .partition_name = "", .partition_num = -1,
};
std::vector<std::string> expected_result{"/dev/block/pci/pci0000:00/0000:00:1f.2/mmcblk0"};
@@ -197,7 +239,7 @@
TEST(devices, get_block_device_symlinks_pci_bad_format) {
const char* platform_device = "/devices/do/not/match";
uevent uevent = {
- .path = "/devices/pci//mmcblk0", .partition_name = nullptr, .partition_num = -1,
+ .path = "/devices/pci//mmcblk0", .partition_name = "", .partition_num = -1,
};
std::vector<std::string> expected_result{};
@@ -207,7 +249,7 @@
TEST(devices, get_block_device_symlinks_success_vbd) {
const char* platform_device = "/devices/do/not/match";
uevent uevent = {
- .path = "/devices/vbd-1234/mmcblk0", .partition_name = nullptr, .partition_num = -1,
+ .path = "/devices/vbd-1234/mmcblk0", .partition_name = "", .partition_num = -1,
};
std::vector<std::string> expected_result{"/dev/block/vbd/1234/mmcblk0"};
@@ -217,7 +259,7 @@
TEST(devices, get_block_device_symlinks_vbd_bad_format) {
const char* platform_device = "/devices/do/not/match";
uevent uevent = {
- .path = "/devices/vbd-/mmcblk0", .partition_name = nullptr, .partition_num = -1,
+ .path = "/devices/vbd-/mmcblk0", .partition_name = "", .partition_num = -1,
};
std::vector<std::string> expected_result{};
@@ -228,7 +270,7 @@
const char* platform_device = "/devices/soc.0/f9824900.sdhci";
uevent uevent = {
.path = "/devices/soc.0/not_the_device/mmc_host/mmc0/mmc0:0001/block/mmcblk0p1",
- .partition_name = nullptr,
+ .partition_name = "",
.partition_num = -1,
};
std::vector<std::string> expected_result;
diff --git a/init/init.cpp b/init/init.cpp
index 543f38e..6c1c541 100644
--- a/init/init.cpp
+++ b/init/init.cpp
@@ -61,6 +61,7 @@
#include "bootchart.h"
#include "devices.h"
#include "fs_mgr.h"
+#include "fs_mgr_avb.h"
#include "import_parser.h"
#include "init_parser.h"
#include "keychords.h"
@@ -482,42 +483,73 @@
}
}
-static constexpr char android_dt_dir[] = "/proc/device-tree/firmware/android";
-
-static bool is_dt_compatible() {
- std::string dt_value;
- std::string file_name = StringPrintf("%s/compatible", android_dt_dir);
-
- 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") {
+/* Reads the content of device tree file into dt_value.
+ * Returns true if the read is success, 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()) {
+ dt_value->pop_back(); // Trim the trailing '\0' out.
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");
+static const std::string kAndroidDtDir("/proc/device-tree/firmware/android/");
- if (android::base::ReadFileToString(file_name, &dt_value)) {
- dt_value.resize(dt_value.size() - 1);
- if (dt_value == "android,fstab") {
+static bool is_dt_value_expected(const std::string& dt_file_suffix,
+ const std::string& expected_value) {
+ std::string dt_value;
+ std::string file_name = kAndroidDtDir + dt_file_suffix;
+
+ if (read_dt_file(file_name, &dt_value)) {
+ if (dt_value == expected_value) {
return true;
}
}
-
return false;
}
+static inline bool is_dt_compatible() {
+ return is_dt_value_expected("compatible", "android,firmware");
+}
+
+static inline bool is_dt_fstab_compatible() {
+ return is_dt_value_expected("fstab/compatible", "android,fstab");
+}
+
+static inline bool is_dt_vbmeta_compatible() {
+ return is_dt_value_expected("vbmeta/compatible", "android,vbmeta");
+}
+
+// Gets the vbmeta config from device tree. Specifically, the 'parts' and 'by_name_prefix'.
+// /{
+// firmware {
+// android {
+// vbmeta {
+// compatible = "android,vbmeta";
+// parts = "vbmeta,boot,system,vendor"
+// by_name_prefix="/dev/block/platform/soc.0/f9824900.sdhci/by-name/"
+// };
+// };
+// };
+// }
+static bool get_vbmeta_config_from_dt(std::string* vbmeta_partitions,
+ std::string* device_file_by_name_prefix) {
+ std::string file_name = kAndroidDtDir + "vbmeta/parts";
+ if (!read_dt_file(file_name, vbmeta_partitions)) return false;
+
+ file_name = kAndroidDtDir + "vbmeta/by_name_prefix";
+ if (!read_dt_file(file_name, device_file_by_name_prefix)) return false;
+
+ return true;
+}
+
static void process_kernel_dt() {
if (!is_dt_compatible()) return;
- std::unique_ptr<DIR, int(*)(DIR*)>dir(opendir(android_dt_dir), closedir);
+ std::unique_ptr<DIR, int (*)(DIR*)> dir(opendir(kAndroidDtDir.c_str()), closedir);
if (!dir) return;
std::string dt_file;
@@ -527,7 +559,7 @@
continue;
}
- std::string file_name = StringPrintf("%s/%s", android_dt_dir, dp->d_name);
+ std::string file_name = kAndroidDtDir + dp->d_name;
android::base::ReadFileToString(file_name, &dt_file);
std::replace(dt_file.begin(), dt_file.end(), ',', '.');
@@ -920,38 +952,100 @@
}
}
-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 << "'";
+// Creates "/dev/block/dm-XX" for dm-verity by running coldboot on /sys/block/dm-XX.
+static void device_init_dm_device(const std::string& dm_device) {
+ const std::string device_name(basename(dm_device.c_str()));
+ const std::string syspath = "/sys/block/" + device_name;
+
+ device_init(syspath.c_str(), [&](uevent* uevent) -> coldboot_action_t {
+ if (uevent->device_name == device_name) {
+ LOG(VERBOSE) << "early_mount: creating dm-verity device : " << dm_device;
+ return COLDBOOT_STOP;
+ }
+ return COLDBOOT_CONTINUE;
+ });
+ device_close();
+}
+
+static bool vboot_1_0_mount_partitions(const std::vector<fstab_rec*>& fstab_recs) {
+ if (fstab_recs.empty()) return false;
+
+ for (auto rec : fstab_recs) {
+ bool need_create_dm_device = false;
+ if (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 /* wait_for_verity_dev */);
+ if (ret == FS_MGR_SETUP_VERITY_DISABLED) {
+ LOG(INFO) << "verity disabled for '" << rec->mount_point << "'";
+ } else if (ret == FS_MGR_SETUP_VERITY_SUCCESS) {
+ need_create_dm_device = true;
+ } else {
+ PLOG(ERROR) << "early_mount: failed to setup verity for '" << rec->mount_point
+ << "'";
+ return false;
+ }
+ }
+ if (need_create_dm_device) {
+ // The exact block device name (rec->blk_device) is changed to "/dev/block/dm-XX".
+ // Need to create it because ueventd isn't started during early mount.
+ device_init_dm_device(rec->blk_device);
+ }
+ if (fs_mgr_do_mount_one(rec)) {
+ PLOG(ERROR) << "early_mount: failed to mount '" << 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;
- });
- }
-
- if (rec && fs_mgr_do_mount_one(rec)) {
- PLOG(ERROR) << "early_mount: Failed to mount '" << rec->mount_point << "'";
- return false;
}
return true;
}
+static bool vboot_2_0_mount_partitions(const std::vector<fstab_rec*>& fstab_recs,
+ const std::string& device_file_by_name_prefix) {
+ if (fstab_recs.empty()) return false;
+
+ FsManagerAvbUniquePtr avb_handle = FsManagerAvbHandle::Open(device_file_by_name_prefix);
+ if (!avb_handle) {
+ LOG(INFO) << "Failed to Open FsManagerAvbHandle";
+ return false;
+ }
+
+ for (auto rec : fstab_recs) {
+ bool need_create_dm_device = false;
+ if (fs_mgr_is_avb(rec)) {
+ if (avb_handle->AvbHashtreeDisabled()) {
+ LOG(INFO) << "avb hashtree disabled for '" << rec->mount_point << "'";
+ } else if (avb_handle->SetUpAvb(rec, false /* wait_for_verity_dev */)) {
+ need_create_dm_device = true;
+ } else {
+ PLOG(ERROR) << "early_mount: failed to set up AVB on partition: '"
+ << rec->mount_point << "'";
+ return false;
+ }
+ }
+ if (need_create_dm_device) {
+ // The exact block device name (rec->blk_device) is changed to "/dev/block/dm-XX".
+ // Need to create it because ueventd isn't started during early mount.
+ device_init_dm_device(rec->blk_device);
+ }
+ if (fs_mgr_do_mount_one(rec)) {
+ PLOG(ERROR) << "early_mount: failed to mount '" << rec->mount_point << "'";
+ return false;
+ }
+ }
+
+ return true;
+}
+
+static bool mount_early_partitions(const std::vector<fstab_rec*>& fstab_recs,
+ const std::string& device_file_by_name_prefix) {
+ if (is_dt_vbmeta_compatible()) { // AVB (external/avb) is used to setup dm-verity.
+ return vboot_2_0_mount_partitions(fstab_recs, device_file_by_name_prefix);
+ } else {
+ return vboot_1_0_mount_partitions(fstab_recs);
+ }
+}
+
// Creates devices with uevent->partition_name matching one in the in/out
// partition_names. Note that the partition_names MUST have A/B suffix
// when A/B is used. Found partitions will then be removed from the
@@ -961,21 +1055,17 @@
return;
}
device_init(nullptr, [=](uevent* uevent) -> coldboot_action_t {
- if (!strncmp(uevent->subsystem, "firmware", 8)) {
- return COLDBOOT_CONTINUE;
- }
-
// we need platform devices to create symlinks
- if (!strncmp(uevent->subsystem, "platform", 8)) {
+ if (uevent->subsystem == "platform") {
return COLDBOOT_CREATE;
}
// Ignore everything that is not a block device
- if (strncmp(uevent->subsystem, "block", 5)) {
+ if (uevent->subsystem != "block") {
return COLDBOOT_CONTINUE;
}
- if (uevent->partition_name) {
+ if (!uevent->partition_name.empty()) {
// match partition names to create device nodes for partitions
// both partition_names and uevent->partition_name have A/B suffix when A/B is used
auto iter = partition_names->find(uevent->partition_name);
@@ -994,12 +1084,10 @@
});
}
-static bool get_early_partitions(const std::vector<fstab_rec*>& early_fstab_recs,
- std::set<std::string>* out_partitions, bool* out_need_verity) {
+static bool vboot_1_0_early_partitions(const std::vector<fstab_rec*>& early_fstab_recs,
+ std::set<std::string>* out_partitions,
+ bool* out_need_verity) {
std::string meta_partition;
- out_partitions->clear();
- *out_need_verity = false;
-
for (auto fstab_rec : early_fstab_recs) {
// don't allow verifyatboot for early mounted partitions
if (fs_mgr_is_verifyatboot(fstab_rec)) {
@@ -1038,6 +1126,40 @@
return true;
}
+// a.k.a. AVB (external/avb)
+static bool vboot_2_0_early_partitions(std::set<std::string>* out_partitions, bool* out_need_verity,
+ std::string* out_device_file_by_name_prefix) {
+ std::string vbmeta_partitions;
+ if (!get_vbmeta_config_from_dt(&vbmeta_partitions, out_device_file_by_name_prefix)) {
+ return false;
+ }
+ // libavb verifies AVB metadata on all verified partitions at once.
+ // e.g., The vbmeta_partitions will be "vbmeta,boot,system,vendor"
+ // for libavb to verify metadata, even if we only need to early mount /vendor.
+ std::vector<std::string> partitions = android::base::Split(vbmeta_partitions, ",");
+ std::string ab_suffix = fs_mgr_get_slot_suffix();
+ for (const auto& partition : partitions) {
+ out_partitions->emplace(partition + ab_suffix);
+ }
+ *out_need_verity = true;
+ return true;
+}
+
+static bool get_early_partitions(const std::vector<fstab_rec*>& early_fstab_recs,
+ std::set<std::string>* out_partitions, bool* out_need_verity,
+ std::string* out_device_file_by_name_prefix) {
+ *out_need_verity = false;
+ out_partitions->clear();
+ out_device_file_by_name_prefix->clear();
+
+ if (is_dt_vbmeta_compatible()) { // AVB (external/avb) is used to setup dm-verity.
+ return vboot_2_0_early_partitions(out_partitions, out_need_verity,
+ out_device_file_by_name_prefix);
+ } else {
+ return vboot_1_0_early_partitions(early_fstab_recs, out_partitions, out_need_verity);
+ }
+}
+
/* Early mount vendor and ODM partitions. The fstab is read from device-tree. */
static bool early_mount() {
// skip early mount if we're in recovery mode
@@ -1072,9 +1194,11 @@
if (early_fstab_recs.empty()) return true;
bool need_verity;
+ std::string device_file_by_name_prefix;
std::set<std::string> partition_names;
// partition_names MUST have A/B suffix when A/B is used
- if (!get_early_partitions(early_fstab_recs, &partition_names, &need_verity)) {
+ if (!get_early_partitions(early_fstab_recs, &partition_names, &need_verity,
+ &device_file_by_name_prefix)) {
return false;
}
@@ -1097,10 +1221,9 @@
[&](uevent* uevent) -> coldboot_action_t { return COLDBOOT_STOP; });
}
- for (auto fstab_rec : early_fstab_recs) {
- if (!early_mount_one(fstab_rec)) goto done;
+ if (mount_early_partitions(early_fstab_recs, device_file_by_name_prefix)) {
+ success = true;
}
- success = true;
done:
device_close();
diff --git a/init/log.cpp b/init/log.cpp
index ee6489b..0615730 100644
--- a/init/log.cpp
+++ b/init/log.cpp
@@ -21,7 +21,6 @@
#include <string.h>
#include <android-base/logging.h>
-#include <netlink/netlink.h>
#include <selinux/selinux.h>
void InitKernelLogging(char* argv[]) {
@@ -41,24 +40,6 @@
android::base::InitLogging(argv, &android::base::KernelLogger);
}
-static void selinux_avc_log(char* buf, size_t buf_len) {
- size_t str_len = strnlen(buf, buf_len);
-
- // trim newline at end of string
- buf[str_len - 1] = '\0';
-
- struct nl_sock* sk = nl_socket_alloc();
- if (sk == NULL) {
- return;
- }
- nl_connect(sk, NETLINK_AUDIT);
- int result;
- do {
- result = nl_send_simple(sk, AUDIT_USER_AVC, 0, buf, str_len);
- } while (result == -NLE_INTR);
- nl_socket_free(sk);
-}
-
int selinux_klog_callback(int type, const char *fmt, ...) {
android::base::LogSeverity severity = android::base::ERROR;
if (type == SELINUX_WARNING) {
@@ -69,15 +50,8 @@
char buf[1024];
va_list ap;
va_start(ap, fmt);
- int res = vsnprintf(buf, sizeof(buf), fmt, ap);
+ vsnprintf(buf, sizeof(buf), fmt, ap);
va_end(ap);
- if (res <= 0) {
- return 0;
- }
- if (type == SELINUX_AVC) {
- selinux_avc_log(buf, sizeof(buf));
- } else {
- android::base::KernelLogger(android::base::MAIN, severity, "selinux", nullptr, 0, buf);
- }
+ android::base::KernelLogger(android::base::MAIN, severity, "selinux", nullptr, 0, buf);
return 0;
}
diff --git a/init/reboot.cpp b/init/reboot.cpp
index 8de3c78..d9ebd91 100644
--- a/init/reboot.cpp
+++ b/init/reboot.cpp
@@ -46,6 +46,7 @@
#include <cutils/android_reboot.h>
#include <fs_mgr.h>
#include <logwrap/logwrap.h>
+#include <private/android_filesystem_config.h>
#include "property_service.h"
#include "service.h"
@@ -305,7 +306,8 @@
Timer t;
LOG(INFO) << "Reboot start, reason: " << reason << ", rebootTarget: " << rebootTarget;
- android::base::WriteStringToFile(StringPrintf("%s\n", reason.c_str()), LAST_REBOOT_REASON_FILE);
+ android::base::WriteStringToFile(StringPrintf("%s\n", reason.c_str()), LAST_REBOOT_REASON_FILE,
+ S_IRUSR | S_IWUSR, AID_SYSTEM, AID_SYSTEM);
if (cmd == ANDROID_RB_THERMOFF) { // do not wait if it is thermal
DoThermalOff();
diff --git a/libcutils/Android.bp b/libcutils/Android.bp
index f668f18..bb82f4d 100644
--- a/libcutils/Android.bp
+++ b/libcutils/Android.bp
@@ -24,7 +24,6 @@
"socket_inaddr_any_server_unix.c",
"socket_local_client_unix.c",
"socket_local_server_unix.c",
- "socket_loopback_server_unix.c",
"socket_network_client_unix.c",
"sockets_unix.cpp",
"str_parms.c",
diff --git a/libcutils/include/cutils/sockets.h b/libcutils/include/cutils/sockets.h
index d724dd6..b24468b 100644
--- a/libcutils/include/cutils/sockets.h
+++ b/libcutils/include/cutils/sockets.h
@@ -88,8 +88,6 @@
cutils_socket_t socket_network_client(const char* host, int port, int type);
int socket_network_client_timeout(const char* host, int port, int type,
int timeout, int* getaddrinfo_error);
-int socket_loopback_server(int port, int type);
-int socket_loopback_server6(int port, int type);
int socket_local_server(const char* name, int namespaceId, int type);
int socket_local_server_bind(int s, const char* name, int namespaceId);
int socket_local_client_connect(int fd, const char *name, int namespaceId,
diff --git a/libcutils/socket_loopback_server_unix.c b/libcutils/socket_loopback_server_unix.c
deleted file mode 100644
index 7b92fd6..0000000
--- a/libcutils/socket_loopback_server_unix.c
+++ /dev/null
@@ -1,88 +0,0 @@
-/*
-** Copyright 2006, 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 <stddef.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-
-#define LISTEN_BACKLOG 4
-
-#if !defined(_WIN32)
-#include <sys/socket.h>
-#include <sys/select.h>
-#include <sys/types.h>
-#include <netinet/in.h>
-#endif
-
-#include <cutils/sockets.h>
-
-static int _socket_loopback_server(int family, int type, struct sockaddr * addr, size_t size)
-{
- int s, n;
-
- s = socket(family, type, 0);
- if(s < 0)
- return -1;
-
- n = 1;
- setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (const char *) &n, sizeof(n));
-
- if(bind(s, addr, size) < 0) {
- close(s);
- return -1;
- }
-
- if (type == SOCK_STREAM) {
- int ret;
-
- ret = listen(s, LISTEN_BACKLOG);
-
- if (ret < 0) {
- close(s);
- return -1;
- }
- }
-
- return s;
-}
-
-/* open listen() port on loopback IPv6 interface */
-int socket_loopback_server6(int port, int type)
-{
- struct sockaddr_in6 addr;
-
- memset(&addr, 0, sizeof(addr));
- addr.sin6_family = AF_INET6;
- addr.sin6_port = htons(port);
- addr.sin6_addr = in6addr_loopback;
-
- return _socket_loopback_server(AF_INET6, type, (struct sockaddr *) &addr, sizeof(addr));
-}
-
-/* open listen() port on loopback interface */
-int socket_loopback_server(int port, int type)
-{
- struct sockaddr_in addr;
-
- memset(&addr, 0, sizeof(addr));
- addr.sin_family = AF_INET;
- addr.sin_port = htons(port);
- addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
-
- return _socket_loopback_server(AF_INET, type, (struct sockaddr *) &addr, sizeof(addr));
-}
diff --git a/liblog/event.logtags b/liblog/event.logtags
index 301e885..0a3b650 100644
--- a/liblog/event.logtags
+++ b/liblog/event.logtags
@@ -29,6 +29,7 @@
# 4: Number of allocations
# 5: Id
# 6: Percent
+# s: Number of seconds (monotonic time)
# Default value for data of type int/long is 2 (bytes).
#
# TODO: generate ".java" and ".h" files with integer constants from this file.
diff --git a/liblog/event_tag_map.cpp b/liblog/event_tag_map.cpp
index 0b977c2..73ed16f 100644
--- a/liblog/event_tag_map.cpp
+++ b/liblog/event_tag_map.cpp
@@ -229,9 +229,16 @@
return it->second;
}
+// The position after the end of a valid section of the tag string,
+// caller makes sure delimited appropriately.
+static const char* endOfTag(const char* cp) {
+ while (*cp && (isalnum(*cp) || strchr("_.-@,", *cp))) ++cp;
+ return cp;
+}
+
// Scan one tag line.
//
-// "*pData" should be pointing to the first digit in the tag number. On
+// "pData" should be pointing to the first digit in the tag number. On
// successful return, it will be pointing to the last character in the
// tag line (i.e. the character before the start of the next line).
//
@@ -241,10 +248,11 @@
// data and it will outlive the call.
//
// Returns 0 on success, nonzero on failure.
-static int scanTagLine(EventTagMap* map, char** pData, int lineNum) {
- char* cp;
- unsigned long val = strtoul(*pData, &cp, 10);
- if (cp == *pData) {
+static int scanTagLine(EventTagMap* map, const char*& pData, int lineNum) {
+ char* ep;
+ unsigned long val = strtoul(pData, &ep, 10);
+ const char* cp = ep;
+ if (cp == pData) {
if (lineNum) {
fprintf(stderr, OUT_TAG ": malformed tag number on line %d\n", lineNum);
}
@@ -273,14 +281,13 @@
}
const char* tag = cp;
- // Determine whether "c" is a valid tag char.
- while (isalnum(*++cp) || (*cp == '_')) {
- }
+ cp = endOfTag(cp);
size_t tagLen = cp - tag;
if (!isspace(*cp)) {
if (lineNum) {
- fprintf(stderr, OUT_TAG ": invalid tag chars on line %d\n", lineNum);
+ fprintf(stderr, OUT_TAG ": invalid tag char %c on line %d\n", *cp,
+ lineNum);
}
errno = EINVAL;
return -1;
@@ -311,9 +318,9 @@
while (*cp != '\n') ++cp;
#ifdef DEBUG
- fprintf(stderr, "%d: %p: %.*s\n", lineNum, tag, (int)(cp - *pData), *pData);
+ fprintf(stderr, "%d: %p: %.*s\n", lineNum, tag, (int)(cp - pData), pData);
#endif
- *pData = cp;
+ pData = cp;
if (lineNum) {
if (map->emplaceUnique(tagIndex,
@@ -341,9 +348,9 @@
// Parse the tags out of the file.
static int parseMapLines(EventTagMap* map, size_t which) {
- char* cp = static_cast<char*>(map->mapAddr[which]);
+ const char* cp = static_cast<char*>(map->mapAddr[which]);
size_t len = map->mapLen[which];
- char* endp = cp + len;
+ const char* endp = cp + len;
// insist on EOL at EOF; simplifies parsing and null-termination
if (!len || (*(endp - 1) != '\n')) {
@@ -370,7 +377,7 @@
lineStart = false;
} else if (isdigit(*cp)) {
// looks like a tag; scan it out
- if (scanTagLine(map, &cp, lineNum) != 0) {
+ if (scanTagLine(map, cp, lineNum) != 0) {
if (!which || (errno != EMLINK)) {
return -1;
}
@@ -495,14 +502,13 @@
int ret = asprintf(&buf, command_template, tag);
if (ret > 0) {
// Add some buffer margin for an estimate of the full return content.
- char* cp;
size_t size =
ret - strlen(command_template) +
strlen("65535\n4294967295\t?\t\t\t?\t# uid=32767\n\n\f?success?");
if (size > (size_t)ret) {
- cp = static_cast<char*>(realloc(buf, size));
- if (cp) {
- buf = cp;
+ char* np = static_cast<char*>(realloc(buf, size));
+ if (np) {
+ buf = np;
} else {
size = ret;
}
@@ -512,10 +518,12 @@
// Ask event log tag service for an existing entry
if (__send_log_msg(buf, size) >= 0) {
buf[size - 1] = '\0';
- unsigned long val = strtoul(buf, &cp, 10); // return size
+ char* ep;
+ unsigned long val = strtoul(buf, &ep, 10); // return size
+ const char* cp = ep;
if ((buf != cp) && (val > 0) && (*cp == '\n')) { // truncation OK
++cp;
- if (!scanTagLine(map, &cp, 0)) {
+ if (!scanTagLine(map, cp, 0)) {
free(buf);
return map->find(tag);
}
@@ -573,8 +581,9 @@
LIBLOG_ABI_PUBLIC int android_lookupEventTagNum(EventTagMap* map,
const char* tagname,
const char* format, int prio) {
- size_t len = strlen(tagname);
- if (!len) {
+ const char* ep = endOfTag(tagname);
+ size_t len = ep - tagname;
+ if (!len || *ep) {
errno = EINVAL;
return -1;
}
diff --git a/liblog/include/log/log_event_list.h b/liblog/include/log/log_event_list.h
index 55953fc..057be5d 100644
--- a/liblog/include/log/log_event_list.h
+++ b/liblog/include/log/log_event_list.h
@@ -17,6 +17,7 @@
#ifndef _LIBS_LOG_EVENT_LIST_H
#define _LIBS_LOG_EVENT_LIST_H
+#include <errno.h>
#include <stdint.h>
#if (defined(__cplusplus) && defined(_USING_LIBCXX))
@@ -148,6 +149,7 @@
return ctx;
}
+ /* return errors or transmit status */
int status() const {
return ret;
}
@@ -209,14 +211,16 @@
}
int write(log_id_t id = LOG_ID_EVENTS) {
+ /* facilitate -EBUSY retry */
+ if ((ret == -EBUSY) || (ret > 0)) ret = 0;
int retval = android_log_write_list(ctx, id);
- if (retval < 0) ret = retval;
+ /* existing errors trump transmission errors */
+ if (!ret) ret = retval;
return ret;
}
int operator<<(log_id_t id) {
- int retval = android_log_write_list(ctx, id);
- if (retval < 0) ret = retval;
+ write(id);
android_log_destroy(&ctx);
return ret;
}
diff --git a/liblog/logprint.c b/liblog/logprint.c
index 2ade7b0..b62f8b4 100644
--- a/liblog/logprint.c
+++ b/liblog/logprint.c
@@ -326,6 +326,7 @@
else if (!strcmp(formatString, "uid")) format = FORMAT_MODIFIER_UID;
else if (!strcmp(formatString, "descriptive")) format = FORMAT_MODIFIER_DESCRIPT;
/* clang-format on */
+
#ifndef __MINGW32__
else {
extern char* tzname[2];
@@ -637,7 +638,8 @@
TYPE_MILLISECONDS = '3',
TYPE_ALLOCATIONS = '4',
TYPE_ID = '5',
- TYPE_PERCENT = '6'
+ TYPE_PERCENT = '6',
+ TYPE_MONOTONIC = 's'
};
static int android_log_printBinaryEvent(const unsigned char** pEventData,
@@ -651,7 +653,7 @@
size_t outBufLen = *pOutBufLen;
size_t outBufLenSave = outBufLen;
unsigned char type;
- size_t outCount;
+ size_t outCount = 0;
int result = 0;
const char* cp;
size_t len;
@@ -690,6 +692,7 @@
* 4: Number of allocations
* 5: Id
* 6: Percent
+ * s: Number of seconds (monotonic time)
* Default value for data of type int/long is 2 (bytes).
*/
if (!cp || !findChar(&cp, &len, '(')) {
@@ -921,6 +924,42 @@
outCount = snprintf(outBuf, outBufLen, "ms");
}
break;
+ case TYPE_MONOTONIC: {
+ static const uint64_t minute = 60;
+ static const uint64_t hour = 60 * minute;
+ static const uint64_t day = 24 * hour;
+
+ /* Repaint as unsigned seconds, minutes, hours ... */
+ outBuf -= outCount;
+ outBufLen += outCount;
+ uint64_t val = lval;
+ if (val >= day) {
+ outCount = snprintf(outBuf, outBufLen, "%" PRIu64 "d ", val / day);
+ if (outCount >= outBufLen) break;
+ outBuf += outCount;
+ outBufLen -= outCount;
+ val = (val % day) + day;
+ }
+ if (val >= minute) {
+ if (val >= hour) {
+ outCount = snprintf(outBuf, outBufLen, "%" PRIu64 ":",
+ (val / hour) % (day / hour));
+ if (outCount >= outBufLen) break;
+ outBuf += outCount;
+ outBufLen -= outCount;
+ }
+ outCount =
+ snprintf(outBuf, outBufLen,
+ (val >= hour) ? "%02" PRIu64 ":" : "%" PRIu64 ":",
+ (val / minute) % (hour / minute));
+ if (outCount >= outBufLen) break;
+ outBuf += outCount;
+ outBufLen -= outCount;
+ }
+ outCount = snprintf(outBuf, outBufLen,
+ (val >= minute) ? "%02" PRIu64 : "%" PRIu64 "s",
+ val % minute);
+ } break;
case TYPE_ALLOCATIONS:
outCount = 0;
/* outCount = snprintf(outBuf, outBufLen, " allocations"); */
diff --git a/logcat/event.logtags b/logcat/event.logtags
index 9f05351..efcc817 100644
--- a/logcat/event.logtags
+++ b/logcat/event.logtags
@@ -30,6 +30,7 @@
# 4: Number of allocations
# 5: Id
# 6: Percent
+# s: Number of seconds (monotonic time)
# Default value for data of type int/long is 2 (bytes).
#
# TODO: generate ".java" and ".h" files with integer constants from this file.
diff --git a/logcat/tests/logcat_test.cpp b/logcat/tests/logcat_test.cpp
index 21868f2..e487a97 100644
--- a/logcat/tests/logcat_test.cpp
+++ b/logcat/tests/logcat_test.cpp
@@ -17,6 +17,7 @@
#include <ctype.h>
#include <dirent.h>
#include <signal.h>
+#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -31,6 +32,7 @@
#include <android-base/file.h>
#include <gtest/gtest.h>
+#include <log/event_tag_map.h>
#include <log/log.h>
#include <log/log_event_list.h>
@@ -47,6 +49,16 @@
#define BIG_BUFFER (5 * 1024)
+// rest(), let the logs settle.
+//
+// logd is in a background cgroup and under extreme load can take up to
+// 3 seconds to land a log entry. Under moderate load we can do with 200ms.
+static void rest() {
+ static const useconds_t restPeriod = 200000;
+
+ usleep(restPeriod);
+}
+
// enhanced version of LOG_FAILURE_RETRY to add support for EAGAIN and
// non-syscall libs. Since we are only using this in the emergency of
// a signal to stuff a terminating code into the logs, we will spin rather
@@ -70,7 +82,7 @@
#undef LOG_TAG
#define LOG_TAG "inject"
RLOGE(logcat_executable ".buckets");
- sleep(1);
+ rest();
ASSERT_TRUE(NULL !=
(fp = logcat_popen(
@@ -1412,7 +1424,7 @@
LOG_FAILURE_RETRY(__android_log_print(ANDROID_LOG_WARN, logcat_regex_prefix,
logcat_regex_prefix "_aaaa"));
// Let the logs settle
- sleep(1);
+ rest();
ASSERT_TRUE(NULL != (fp = logcat_popen(ctx, buffer)));
@@ -1450,8 +1462,7 @@
LOG_FAILURE_RETRY(
__android_log_print(ANDROID_LOG_WARN, "logcat_test", "logcat_test"));
- // Let the logs settle
- sleep(1);
+ rest();
ASSERT_TRUE(NULL != (fp = logcat_popen(ctx, buffer)));
@@ -1476,8 +1487,7 @@
static bool End_to_End(const char* tag, const char* fmt, ...) {
logcat_define(ctx);
- FILE* fp = logcat_popen(ctx,
- "logcat"
+ FILE* fp = logcat_popen(ctx, logcat_executable
" -v brief"
" -b events"
" -v descriptive"
@@ -1523,13 +1533,12 @@
// Help us pinpoint where things went wrong ...
fprintf(stderr, "Closest match for\n %s\n is\n %s",
expect.c_str(), lastMatch.c_str());
- } else if (count > 2) {
+ } else if (count > 3) {
fprintf(stderr, "Too many matches (%d) for %s\n", count, expect.c_str());
}
- // Expect one the first time around as either liblogcat.descriptive or
- // logcat.descriptive. Expect two the second time as the other.
- return count == 1 || count == 2;
+ // Three different known tests, we can see pollution from the others
+ return count && (count <= 3);
}
TEST(logcat, descriptive) {
@@ -1537,24 +1546,28 @@
uint32_t tagNo;
const char* tagStr;
};
+ int ret;
{
static const struct tag hhgtg = { 42, "answer" };
android_log_event_list ctx(hhgtg.tagNo);
static const char theAnswer[] = "what is five by seven";
ctx << theAnswer;
- ctx.write();
+ // crafted to rest at least once after, and rest between retries.
+ for (ret = -EBUSY; ret == -EBUSY; rest()) ret = ctx.write();
+ EXPECT_LE(0, ret);
EXPECT_TRUE(
End_to_End(hhgtg.tagStr, "to life the universe etc=%s", theAnswer));
}
{
static const struct tag sync = { 2720, "sync" };
- static const char id[] = "logcat.decriptive";
+ static const char id[] = ___STRING(logcat) ".descriptive-sync";
{
android_log_event_list ctx(sync.tagNo);
ctx << id << (int32_t)42 << (int32_t)-1 << (int32_t)0;
- ctx.write();
+ for (ret = -EBUSY; ret == -EBUSY; rest()) ret = ctx.write();
+ EXPECT_LE(0, ret);
EXPECT_TRUE(End_to_End(sync.tagStr,
"[id=%s,event=42,source=-1,account=0]", id));
}
@@ -1563,7 +1576,8 @@
{
android_log_event_list ctx(sync.tagNo);
ctx << id << (int32_t)43 << (int64_t)-1 << (int32_t)0;
- ctx.write();
+ for (ret = -EBUSY; ret == -EBUSY; rest()) ret = ctx.write();
+ EXPECT_LE(0, ret);
EXPECT_TRUE(End_to_End(sync.tagStr, "[id=%s,event=43,-1,0]", id));
}
@@ -1571,7 +1585,8 @@
{
android_log_event_list ctx(sync.tagNo);
ctx << id << (int32_t)44 << (int32_t)-1 << (int64_t)0;
- ctx.write();
+ for (ret = -EBUSY; ret == -EBUSY; rest()) ret = ctx.write();
+ EXPECT_LE(0, ret);
fprintf(stderr, "Expect a \"Closest match\" message\n");
EXPECT_FALSE(End_to_End(
sync.tagStr, "[id=%s,event=44,source=-1,account=0]", id));
@@ -1583,7 +1598,8 @@
{
android_log_event_list ctx(sync.tagNo);
ctx << (uint64_t)30 << (int32_t)2;
- ctx.write();
+ for (ret = -EBUSY; ret == -EBUSY; rest()) ret = ctx.write();
+ EXPECT_LE(0, ret);
EXPECT_TRUE(
End_to_End(sync.tagStr, "[aggregation time=30ms,count=2]"));
}
@@ -1591,7 +1607,8 @@
{
android_log_event_list ctx(sync.tagNo);
ctx << (uint64_t)31570 << (int32_t)911;
- ctx.write();
+ for (ret = -EBUSY; ret == -EBUSY; rest()) ret = ctx.write();
+ EXPECT_LE(0, ret);
EXPECT_TRUE(
End_to_End(sync.tagStr, "[aggregation time=31.57s,count=911]"));
}
@@ -1602,42 +1619,48 @@
{
android_log_event_list ctx(sync.tagNo);
ctx << (uint32_t)512;
- ctx.write();
+ for (ret = -EBUSY; ret == -EBUSY; rest()) ret = ctx.write();
+ EXPECT_LE(0, ret);
EXPECT_TRUE(End_to_End(sync.tagStr, "current=512B"));
}
{
android_log_event_list ctx(sync.tagNo);
ctx << (uint32_t)3072;
- ctx.write();
+ for (ret = -EBUSY; ret == -EBUSY; rest()) ret = ctx.write();
+ EXPECT_LE(0, ret);
EXPECT_TRUE(End_to_End(sync.tagStr, "current=3KB"));
}
{
android_log_event_list ctx(sync.tagNo);
ctx << (uint32_t)2097152;
- ctx.write();
+ for (ret = -EBUSY; ret == -EBUSY; rest()) ret = ctx.write();
+ EXPECT_LE(0, ret);
EXPECT_TRUE(End_to_End(sync.tagStr, "current=2MB"));
}
{
android_log_event_list ctx(sync.tagNo);
ctx << (uint32_t)2097153;
- ctx.write();
+ for (ret = -EBUSY; ret == -EBUSY; rest()) ret = ctx.write();
+ EXPECT_LE(0, ret);
EXPECT_TRUE(End_to_End(sync.tagStr, "current=2097153B"));
}
{
android_log_event_list ctx(sync.tagNo);
ctx << (uint32_t)1073741824;
- ctx.write();
+ for (ret = -EBUSY; ret == -EBUSY; rest()) ret = ctx.write();
+ EXPECT_LE(0, ret);
EXPECT_TRUE(End_to_End(sync.tagStr, "current=1GB"));
}
{
android_log_event_list ctx(sync.tagNo);
ctx << (uint32_t)3221225472; // 3MB, but on purpose overflowed
- ctx.write();
+ for (ret = -EBUSY; ret == -EBUSY; rest()) ret = ctx.write();
+ EXPECT_LE(0, ret);
EXPECT_TRUE(End_to_End(sync.tagStr, "current=-1GB"));
}
}
@@ -1645,9 +1668,52 @@
{
static const struct tag sync = { 27501, "notification_panel_hidden" };
android_log_event_list ctx(sync.tagNo);
- ctx.write();
+ for (ret = -EBUSY; ret == -EBUSY; rest()) ret = ctx.write();
+ EXPECT_LE(0, ret);
EXPECT_TRUE(End_to_End(sync.tagStr, ""));
}
+
+ {
+ // Invent new entries because existing can not serve
+ EventTagMap* map = android_openEventTagMap(nullptr);
+ ASSERT_TRUE(nullptr != map);
+ static const char name[] = ___STRING(logcat) ".descriptive-monotonic";
+ int myTag = android_lookupEventTagNum(map, name, "(new|1|s)",
+ ANDROID_LOG_UNKNOWN);
+ android_closeEventTagMap(map);
+ ASSERT_NE(-1, myTag);
+
+ const struct tag sync = { (uint32_t)myTag, name };
+
+ {
+ android_log_event_list ctx(sync.tagNo);
+ ctx << (uint32_t)7;
+ for (ret = -EBUSY; ret == -EBUSY; rest()) ret = ctx.write();
+ EXPECT_LE(0, ret);
+ EXPECT_TRUE(End_to_End(sync.tagStr, "new=7s"));
+ }
+ {
+ android_log_event_list ctx(sync.tagNo);
+ ctx << (uint32_t)62;
+ for (ret = -EBUSY; ret == -EBUSY; rest()) ret = ctx.write();
+ EXPECT_LE(0, ret);
+ EXPECT_TRUE(End_to_End(sync.tagStr, "new=1:02"));
+ }
+ {
+ android_log_event_list ctx(sync.tagNo);
+ ctx << (uint32_t)3673;
+ for (ret = -EBUSY; ret == -EBUSY; rest()) ret = ctx.write();
+ EXPECT_LE(0, ret);
+ EXPECT_TRUE(End_to_End(sync.tagStr, "new=1:01:13"));
+ }
+ {
+ android_log_event_list ctx(sync.tagNo);
+ ctx << (uint32_t)(86400 + 7200 + 180 + 58);
+ for (ret = -EBUSY; ret == -EBUSY; rest()) ret = ctx.write();
+ EXPECT_LE(0, ret);
+ EXPECT_TRUE(End_to_End(sync.tagStr, "new=1d 2:03:58"));
+ }
+ }
}
static bool reportedSecurity(const char* command) {
diff --git a/logd/LogStatistics.cpp b/logd/LogStatistics.cpp
index cc30f77..d3167ad 100644
--- a/logd/LogStatistics.cpp
+++ b/logd/LogStatistics.cpp
@@ -248,18 +248,38 @@
std::string(isprune ? "NUM" : ""));
}
+// Helper to truncate name, if too long, and add name dressings
+static void formatTmp(const LogStatistics& stat, const char* nameTmp, uid_t uid,
+ std::string& name, std::string& size, size_t nameLen) {
+ const char* allocNameTmp = nullptr;
+ if (!nameTmp) nameTmp = allocNameTmp = stat.uidToName(uid);
+ if (nameTmp) {
+ size_t lenSpace = std::max(nameLen - name.length(), (size_t)1);
+ size_t len = EntryBaseConstants::total_len -
+ EntryBaseConstants::pruned_len - size.length() -
+ name.length() - lenSpace - 2;
+ size_t lenNameTmp = strlen(nameTmp);
+ while ((len < lenNameTmp) && (lenSpace > 1)) {
+ ++len;
+ --lenSpace;
+ }
+ name += android::base::StringPrintf("%*s", (int)lenSpace, "");
+ if (len < lenNameTmp) {
+ name += "...";
+ nameTmp += lenNameTmp - std::max(len - 3, (size_t)1);
+ }
+ name += nameTmp;
+ free(const_cast<char*>(allocNameTmp));
+ }
+}
+
std::string UidEntry::format(const LogStatistics& stat, log_id_t id) const {
uid_t uid = getUid();
std::string name = android::base::StringPrintf("%u", uid);
- const char* nameTmp = stat.uidToName(uid);
- if (nameTmp) {
- name += android::base::StringPrintf(
- "%*s%s", (int)std::max(6 - name.length(), (size_t)1), "", nameTmp);
- free(const_cast<char*>(nameTmp));
- }
-
std::string size = android::base::StringPrintf("%zu", getSizes());
+ formatTmp(stat, nullptr, uid, name, size, 6);
+
std::string pruned = "";
if (worstUidEnabledForLogid(id)) {
size_t totalDropped = 0;
@@ -366,18 +386,10 @@
uid_t uid = getUid();
pid_t pid = getPid();
std::string name = android::base::StringPrintf("%5u/%u", pid, uid);
- const char* nameTmp = getName();
- if (nameTmp) {
- name += android::base::StringPrintf(
- "%*s%s", (int)std::max(12 - name.length(), (size_t)1), "", nameTmp);
- } else if ((nameTmp = stat.uidToName(uid))) {
- name += android::base::StringPrintf(
- "%*s%s", (int)std::max(12 - name.length(), (size_t)1), "", nameTmp);
- free(const_cast<char*>(nameTmp));
- }
-
std::string size = android::base::StringPrintf("%zu", getSizes());
+ formatTmp(stat, getName(), uid, name, size, 12);
+
std::string pruned = "";
size_t dropped = getDropped();
if (dropped) {
@@ -398,21 +410,10 @@
log_id_t /* id */) const {
uid_t uid = getUid();
std::string name = android::base::StringPrintf("%5u/%u", getTid(), uid);
- const char* nameTmp = getName();
- if (nameTmp) {
- name += android::base::StringPrintf(
- "%*s%s", (int)std::max(12 - name.length(), (size_t)1), "", nameTmp);
- } else if ((nameTmp = stat.uidToName(uid))) {
- // if we do not have a PID name, lets punt to try UID name?
- name += android::base::StringPrintf(
- "%*s%s", (int)std::max(12 - name.length(), (size_t)1), "", nameTmp);
- free(const_cast<char*>(nameTmp));
- // We tried, better to not have a name at all, we still
- // have TID/UID by number to report in any case.
- }
-
std::string size = android::base::StringPrintf("%zu", getSizes());
+ formatTmp(stat, getName(), uid, name, size, 12);
+
std::string pruned = "";
size_t dropped = getDropped();
if (dropped) {
diff --git a/logd/event.logtags b/logd/event.logtags
index 39063a9..fa13a62 100644
--- a/logd/event.logtags
+++ b/logd/event.logtags
@@ -29,6 +29,7 @@
# 4: Number of allocations
# 5: Id
# 6: Percent
+# s: Number of seconds (monotonic time)
# Default value for data of type int/long is 2 (bytes).
#
# TODO: generate ".java" and ".h" files with integer constants from this file.
diff --git a/rootdir/init.rc b/rootdir/init.rc
index 17dade4..a43b0e1 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -406,7 +406,7 @@
mkdir /data/misc/boottrace 0771 system shell
mkdir /data/misc/update_engine 0700 root root
mkdir /data/misc/trace 0700 root root
- mkdir /data/misc/reboot 0700 root root
+ mkdir /data/misc/reboot 0700 system system
# profile file layout
mkdir /data/misc/profiles 0771 system system
mkdir /data/misc/profiles/cur 0771 system system