Merge changes I443e733f,If1e89a67,I0481d87a
* changes:
init: document previously undocumentary service options
init: alphabetize service options in README.md
init: alphabetize service options
diff --git a/OWNERS b/OWNERS
index 682a067..1d319af 100644
--- a/OWNERS
+++ b/OWNERS
@@ -1 +1,5 @@
enh@google.com
+per-file libsysutils/src/Netlink* = ek@google.com
+per-file libsysutils/src/Netlink* = lorenzo@google.com
+per-file libsysutils/include/sysutils/Netlink* = ek@google.com
+per-file libsysutils/include/sysutils/Netlink* = lorenzo@google.com
diff --git a/adb/Android.bp b/adb/Android.bp
index 0858a6c..bbf7cb4 100644
--- a/adb/Android.bp
+++ b/adb/Android.bp
@@ -12,6 +12,325 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+cc_defaults {
+ name: "adb_defaults",
+
+ cflags: [
+ "-Wall",
+ "-Wextra",
+ "-Werror",
+ "-Wno-unused-parameter",
+ "-Wno-missing-field-initializers",
+ "-Wvla",
+ ],
+ rtti: true,
+
+ clang_cflags: [
+ "-Wexit-time-destructors",
+ "-Wthread-safety",
+ ],
+
+ use_version_lib: true,
+
+ compile_multilib: "first",
+ product_variables: {
+ debuggable: {
+ cflags: [
+ "-DALLOW_ADBD_ROOT",
+ "-DALLOW_ADBD_DISABLE_VERITY",
+ "-DALLOW_ADBD_NO_AUTH",
+ ],
+ },
+ },
+
+ target: {
+ android: {
+ cflags: ["-DADB_HOST=0"],
+ },
+
+ host: {
+ cflags: ["-DADB_HOST=1"],
+ },
+
+ darwin: {
+ host_ldlibs: [
+ "-lpthread",
+ "-framework CoreFoundation",
+ "-framework IOKit",
+ "-lobjc",
+ ],
+ },
+
+ windows: {
+ cflags: [
+ // Define windows.h and tchar.h Unicode preprocessor symbols so that
+ // CreateFile(), _tfopen(), etc. map to versions that take wchar_t*, breaking the
+ // build if you accidentally pass char*. Fix by calling like:
+ // std::wstring path_wide;
+ // if (!android::base::UTF8ToWide(path_utf8, &path_wide)) { /* error handling */ }
+ // CreateFileW(path_wide.c_str());
+ "-DUNICODE=1",
+ "-D_UNICODE=1",
+
+ // -std=gnu++14 doesn't set _GNU_SOURCE on Windows.
+ "-D_GNU_SOURCE",
+ ],
+ },
+ },
+}
+
+// libadb
+// =========================================================
+// These files are compiled for both the host and the device.
+libadb_srcs = [
+ "adb.cpp",
+ "adb_io.cpp",
+ "adb_listeners.cpp",
+ "adb_trace.cpp",
+ "adb_utils.cpp",
+ "fdevent.cpp",
+ "services.cpp",
+ "sockets.cpp",
+ "socket_spec.cpp",
+ "sysdeps/errno.cpp",
+ "transport.cpp",
+ "transport_local.cpp",
+ "transport_usb.cpp",
+]
+
+libadb_posix_srcs = [
+ "sysdeps_unix.cpp",
+ "sysdeps/posix/network.cpp",
+]
+
+libadb_test_srcs = [
+ "adb_io_test.cpp",
+ "adb_listeners_test.cpp",
+ "adb_utils_test.cpp",
+ "fdevent_test.cpp",
+ "socket_spec_test.cpp",
+ "socket_test.cpp",
+ "sysdeps_test.cpp",
+ "sysdeps/stat_test.cpp",
+ "transport_test.cpp",
+]
+
+cc_library_host_static {
+ name: "libadb_host",
+ defaults: ["adb_defaults"],
+
+ srcs: libadb_srcs + [
+ "client/auth.cpp",
+ "client/usb_libusb.cpp",
+ "client/usb_dispatch.cpp",
+ "client/transport_mdns.cpp",
+ ],
+
+ target: {
+ linux: {
+ srcs: ["client/usb_linux.cpp"],
+ },
+ darwin: {
+ srcs: ["client/usb_osx.cpp"],
+ },
+
+ not_windows: {
+ srcs: libadb_posix_srcs,
+ },
+ windows: {
+ enabled: true,
+ srcs: [
+ "client/usb_windows.cpp",
+ "sysdeps_win32.cpp",
+ "sysdeps/win32/errno.cpp",
+ "sysdeps/win32/stat.cpp",
+ ],
+ shared_libs: ["AdbWinApi"],
+ },
+ },
+
+ static_libs: [
+ "libbase",
+ "libcrypto_utils",
+ "libcrypto",
+ "libdiagnose_usb",
+ "libmdnssd",
+ "libusb",
+ ],
+}
+
+cc_test_host {
+ name: "adb_test",
+ defaults: ["adb_defaults"],
+ srcs: libadb_test_srcs,
+ static_libs: [
+ "libadb_host",
+ "libbase",
+ "libcutils",
+ "libcrypto_utils",
+ "libcrypto",
+ "libmdnssd",
+ "libdiagnose_usb",
+ "libusb",
+ ],
+}
+
+cc_binary_host {
+ name: "adb",
+ tags: ["debug"],
+
+ defaults: ["adb_defaults"],
+
+ srcs: [
+ "client/adb_client.cpp",
+ "client/bugreport.cpp",
+ "client/commandline.cpp",
+ "client/file_sync_client.cpp",
+ "client/main.cpp",
+ "client/console.cpp",
+ "client/line_printer.cpp",
+ "shell_service_protocol.cpp",
+ ],
+
+ static_libs: [
+ "libadb_host",
+ "libbase",
+ "libcutils",
+ "libcrypto_utils",
+ "libcrypto",
+ "libdiagnose_usb",
+ "liblog",
+ "libmdnssd",
+ "libusb",
+ ],
+
+ stl: "libc++_static",
+
+ // Don't add anything here, we don't want additional shared dependencies
+ // on the host adb tool, and shared libraries that link against libc++
+ // will violate ODR
+ shared_libs: [],
+
+ target: {
+ darwin: {
+ cflags: [
+ "-Wno-sizeof-pointer-memaccess",
+ ],
+ },
+ windows: {
+ enabled: true,
+ ldflags: ["-municode"],
+ host_ldlibs: [
+ "-lws2_32",
+ "-lgdi32",
+ ],
+
+ shared_libs: ["AdbWinApi"],
+ required: [
+ "AdbWinUsbApi",
+ ],
+ },
+ },
+}
+
+cc_library_static {
+ name: "libadbd",
+ defaults: ["adb_defaults"],
+
+ // libminadbd wants both, for some reason.
+ compile_multilib: "both",
+ srcs: libadb_srcs + libadb_posix_srcs + [
+ "daemon/auth.cpp",
+ "daemon/usb.cpp",
+ "daemon/jdwp_service.cpp",
+ ],
+
+ static_libs: [
+ "libasyncio",
+ "libbootloader_message",
+ "libcrypto_utils",
+ "libcrypto",
+ "libdiagnose_usb",
+ "libqemu_pipe",
+ "libbase",
+ ],
+}
+
+cc_binary {
+ name: "adbd",
+ defaults: ["adb_defaults"],
+
+ // adbd must be static, as it is copied into the recovery image.
+ static_executable: true,
+
+ srcs: [
+ "daemon/main.cpp",
+ "daemon/mdns.cpp",
+ "daemon/file_sync_service.cpp",
+ "daemon/framebuffer_service.cpp",
+ "daemon/remount_service.cpp",
+ "daemon/set_verity_enable_state_service.cpp",
+ "daemon/shell_service.cpp",
+ "shell_service_protocol.cpp",
+ ],
+
+ cflags: [
+ "-D_GNU_SOURCE",
+ "-Wno-deprecated-declarations",
+ ],
+
+ strip: {
+ keep_symbols: true,
+ },
+
+ static_libs: [
+ "libadbd",
+ "libasyncio",
+ "libavb_user",
+ "libbootloader_message",
+ "libcrypto_utils",
+ "libcrypto",
+ "libdiagnose_usb",
+ "libfec",
+ "libfec_rs",
+ "libfs_mgr",
+ "liblog",
+ "libext4_utils",
+ "libmdnssd",
+ "libminijail",
+ "libselinux",
+ "libsquashfs_utils",
+ "libqemu_pipe",
+ "libdebuggerd_handler",
+
+ "libbase",
+ "libcutils",
+ ],
+}
+
+cc_test {
+ name: "adbd_test",
+ defaults: ["adb_defaults"],
+ srcs: libadb_test_srcs + [
+ "daemon/shell_service.cpp",
+ "daemon/shell_service_test.cpp",
+ "shell_service_protocol.cpp",
+ "shell_service_protocol_test.cpp",
+ ],
+
+ static_libs: [
+ "libadbd",
+ "libbase",
+ "libcutils",
+ "libcrypto_utils",
+ "libcrypto",
+ "libdiagnose_usb",
+ "liblog",
+ "libusb",
+ "libmdnssd",
+ ],
+}
+
python_binary_host {
name: "adb_integration_test_adb",
main: "test_adb.py",
diff --git a/adb/Android.mk b/adb/Android.mk
deleted file mode 100644
index e52f0cb..0000000
--- a/adb/Android.mk
+++ /dev/null
@@ -1,387 +0,0 @@
-# Copyright 2005 The Android Open Source Project
-#
-# Android.mk for adb
-#
-
-LOCAL_PATH:= $(call my-dir)
-
-include $(LOCAL_PATH)/../platform_tools_tool_version.mk
-
-adb_host_sanitize :=
-adb_target_sanitize :=
-
-ADB_COMMON_CFLAGS := \
- -frtti \
- -Wall -Wextra -Werror \
- -Wno-unused-parameter \
- -Wno-missing-field-initializers \
- -Wvla \
- -DADB_VERSION="\"$(tool_version)\"" \
-
-ADB_COMMON_posix_CFLAGS := \
- -Wexit-time-destructors \
- -Wthread-safety \
-
-ADB_COMMON_linux_CFLAGS := \
- $(ADB_COMMON_posix_CFLAGS) \
-
-ADB_COMMON_darwin_CFLAGS := \
- $(ADB_COMMON_posix_CFLAGS) \
-
-# Define windows.h and tchar.h Unicode preprocessor symbols so that
-# CreateFile(), _tfopen(), etc. map to versions that take wchar_t*, breaking the
-# build if you accidentally pass char*. Fix by calling like:
-# std::wstring path_wide;
-# if (!android::base::UTF8ToWide(path_utf8, &path_wide)) { /* error handling */ }
-# CreateFileW(path_wide.c_str());
-ADB_COMMON_windows_CFLAGS := \
- -DUNICODE=1 -D_UNICODE=1 \
-
-# libadb
-# =========================================================
-
-# Much of adb is duplicated in bootable/recovery/minadb and fastboot. Changes
-# made to adb rarely get ported to the other two, so the trees have diverged a
-# bit. We'd like to stop this because it is a maintenance nightmare, but the
-# divergence makes this difficult to do all at once. For now, we will start
-# small by moving common files into a static library. Hopefully some day we can
-# get enough of adb in here that we no longer need minadb. https://b/17626262
-LIBADB_SRC_FILES := \
- adb.cpp \
- adb_io.cpp \
- adb_listeners.cpp \
- adb_trace.cpp \
- adb_utils.cpp \
- fdevent.cpp \
- sockets.cpp \
- socket_spec.cpp \
- sysdeps/errno.cpp \
- transport.cpp \
- transport_local.cpp \
- transport_usb.cpp \
-
-LIBADB_TEST_SRCS := \
- adb_io_test.cpp \
- adb_listeners_test.cpp \
- adb_utils_test.cpp \
- fdevent_test.cpp \
- socket_spec_test.cpp \
- socket_test.cpp \
- sysdeps_test.cpp \
- sysdeps/stat_test.cpp \
- transport_test.cpp \
-
-LIBADB_CFLAGS := \
- $(ADB_COMMON_CFLAGS) \
- -fvisibility=hidden \
-
-LIBADB_linux_CFLAGS := \
- $(ADB_COMMON_linux_CFLAGS) \
-
-LIBADB_darwin_CFLAGS := \
- $(ADB_COMMON_darwin_CFLAGS) \
-
-LIBADB_windows_CFLAGS := \
- $(ADB_COMMON_windows_CFLAGS) \
-
-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 \
-
-LIBADB_windows_SRC_FILES := \
- sysdeps_win32.cpp \
- sysdeps/win32/errno.cpp \
- sysdeps/win32/stat.cpp \
- client/usb_dispatch.cpp \
- client/usb_libusb.cpp \
- client/usb_windows.cpp \
-
-LIBADB_TEST_windows_SRCS := \
- sysdeps/win32/errno_test.cpp \
- sysdeps_win32_test.cpp \
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := libadbd_usb
-LOCAL_CFLAGS := $(LIBADB_CFLAGS) -DADB_HOST=0
-LOCAL_SRC_FILES := daemon/usb.cpp
-
-LOCAL_SANITIZE := $(adb_target_sanitize)
-
-# Even though we're building a static library (and thus there's no link step for
-# this to take effect), this adds the includes to our path.
-LOCAL_STATIC_LIBRARIES := libcrypto_utils libcrypto libbase libasyncio
-
-include $(BUILD_STATIC_LIBRARY)
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := libadbd
-LOCAL_CFLAGS := $(LIBADB_CFLAGS) -DADB_HOST=0
-LOCAL_SRC_FILES := \
- $(LIBADB_SRC_FILES) \
- adbd_auth.cpp \
- jdwp_service.cpp \
- sysdeps/posix/network.cpp \
-
-LOCAL_SANITIZE := $(adb_target_sanitize)
-
-# Even though we're building a static library (and thus there's no link step for
-# this to take effect), this adds the includes to our path.
-LOCAL_STATIC_LIBRARIES := libcrypto_utils libcrypto libqemu_pipe libbase
-
-LOCAL_WHOLE_STATIC_LIBRARIES := libadbd_usb
-
-include $(BUILD_STATIC_LIBRARY)
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := libadb
-LOCAL_MODULE_HOST_OS := darwin linux windows
-LOCAL_CFLAGS := $(LIBADB_CFLAGS) -DADB_HOST=1
-LOCAL_CFLAGS_windows := $(LIBADB_windows_CFLAGS)
-LOCAL_CFLAGS_linux := $(LIBADB_linux_CFLAGS)
-LOCAL_CFLAGS_darwin := $(LIBADB_darwin_CFLAGS)
-LOCAL_SRC_FILES := \
- $(LIBADB_SRC_FILES) \
- adb_auth_host.cpp \
- transport_mdns.cpp \
-
-LOCAL_SRC_FILES_darwin := $(LIBADB_darwin_SRC_FILES)
-LOCAL_SRC_FILES_linux := $(LIBADB_linux_SRC_FILES)
-LOCAL_SRC_FILES_windows := $(LIBADB_windows_SRC_FILES)
-
-LOCAL_SANITIZE := $(adb_host_sanitize)
-
-# Even though we're building a static library (and thus there's no link step for
-# this to take effect), this adds the includes to our path.
-LOCAL_STATIC_LIBRARIES := libcrypto_utils libcrypto libbase libmdnssd libusb
-
-LOCAL_C_INCLUDES_windows := development/host/windows/usb/api/
-LOCAL_MULTILIB := first
-
-include $(BUILD_HOST_STATIC_LIBRARY)
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := adbd_test
-LOCAL_CFLAGS := -DADB_HOST=0 $(LIBADB_CFLAGS)
-LOCAL_SRC_FILES := \
- $(LIBADB_TEST_SRCS) \
- $(LIBADB_TEST_linux_SRCS) \
- shell_service.cpp \
- shell_service_protocol.cpp \
- shell_service_protocol_test.cpp \
- shell_service_test.cpp \
-
-LOCAL_SANITIZE := $(adb_target_sanitize)
-LOCAL_STATIC_LIBRARIES := libadbd libcrypto_utils libcrypto libusb libmdnssd
-LOCAL_SHARED_LIBRARIES := liblog libbase libcutils
-include $(BUILD_NATIVE_TEST)
-
-# libdiagnose_usb
-# =========================================================
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := libdiagnose_usb
-LOCAL_MODULE_HOST_OS := darwin linux windows
-LOCAL_CFLAGS := $(LIBADB_CFLAGS)
-LOCAL_SRC_FILES := diagnose_usb.cpp
-# Even though we're building a static library (and thus there's no link step for
-# this to take effect), this adds the includes to our path.
-LOCAL_STATIC_LIBRARIES := libbase
-include $(BUILD_HOST_STATIC_LIBRARY)
-
-# adb_test
-# =========================================================
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := adb_test
-LOCAL_MODULE_HOST_OS := darwin linux windows
-LOCAL_CFLAGS := -DADB_HOST=1 $(LIBADB_CFLAGS)
-LOCAL_CFLAGS_windows := $(LIBADB_windows_CFLAGS)
-LOCAL_CFLAGS_linux := $(LIBADB_linux_CFLAGS)
-LOCAL_CFLAGS_darwin := $(LIBADB_darwin_CFLAGS)
-LOCAL_SRC_FILES := \
- $(LIBADB_TEST_SRCS) \
- adb_client.cpp \
- bugreport.cpp \
- bugreport_test.cpp \
- line_printer.cpp \
- services.cpp \
- shell_service_protocol.cpp \
- shell_service_protocol_test.cpp \
-
-LOCAL_SRC_FILES_linux := $(LIBADB_TEST_linux_SRCS)
-LOCAL_SRC_FILES_darwin := $(LIBADB_TEST_darwin_SRCS)
-LOCAL_SRC_FILES_windows := $(LIBADB_TEST_windows_SRCS)
-LOCAL_SANITIZE := $(adb_host_sanitize)
-LOCAL_STATIC_LIBRARIES := \
- libadb \
- libbase \
- libcrypto_utils \
- libcrypto \
- libcutils \
- libdiagnose_usb \
- libmdnssd \
- libgmock_host \
- libusb \
-
-# Set entrypoint to wmain from sysdeps_win32.cpp instead of main
-LOCAL_LDFLAGS_windows := -municode
-LOCAL_LDLIBS_linux := -lrt -ldl -lpthread
-LOCAL_LDLIBS_darwin := -framework CoreFoundation -framework IOKit -lobjc
-LOCAL_LDLIBS_windows := -lws2_32 -luserenv
-LOCAL_SHARED_LIBRARIES_windows := AdbWinApi
-
-LOCAL_MULTILIB := first
-
-include $(BUILD_HOST_NATIVE_TEST)
-
-# adb host tool
-# =========================================================
-include $(CLEAR_VARS)
-
-LOCAL_LDLIBS_linux := -lrt -ldl -lpthread
-
-LOCAL_LDLIBS_darwin := -lpthread -framework CoreFoundation -framework IOKit -framework Carbon -lobjc
-
-# Use wmain instead of main
-LOCAL_LDFLAGS_windows := -municode
-LOCAL_LDLIBS_windows := -lws2_32 -lgdi32
-LOCAL_SHARED_LIBRARIES_windows := AdbWinApi
-LOCAL_REQUIRED_MODULES_windows := AdbWinUsbApi
-
-LOCAL_SRC_FILES := \
- adb_client.cpp \
- bugreport.cpp \
- client/main.cpp \
- console.cpp \
- commandline.cpp \
- file_sync_client.cpp \
- line_printer.cpp \
- services.cpp \
- shell_service_protocol.cpp \
-
-LOCAL_CFLAGS += \
- $(ADB_COMMON_CFLAGS) \
- -D_GNU_SOURCE \
- -DADB_HOST=1 \
-
-LOCAL_CFLAGS_windows := \
- $(ADB_COMMON_windows_CFLAGS)
-
-LOCAL_CFLAGS_linux := \
- $(ADB_COMMON_linux_CFLAGS) \
-
-LOCAL_CFLAGS_darwin := \
- $(ADB_COMMON_darwin_CFLAGS) \
- -Wno-sizeof-pointer-memaccess -Wno-unused-parameter \
-
-LOCAL_MODULE := adb
-LOCAL_MODULE_TAGS := debug
-LOCAL_MODULE_HOST_OS := darwin linux windows
-
-LOCAL_SANITIZE := $(adb_host_sanitize)
-LOCAL_STATIC_LIBRARIES := \
- libadb \
- libbase \
- libcrypto_utils \
- libcrypto \
- libdiagnose_usb \
- liblog \
- libmdnssd \
- libusb \
-
-# Don't use libcutils on Windows.
-LOCAL_STATIC_LIBRARIES_darwin := libcutils
-LOCAL_STATIC_LIBRARIES_linux := libcutils
-
-LOCAL_CXX_STL := libc++_static
-
-# Don't add anything here, we don't want additional shared dependencies
-# on the host adb tool, and shared libraries that link against libc++
-# will violate ODR
-LOCAL_SHARED_LIBRARIES :=
-
-include $(BUILD_HOST_EXECUTABLE)
-
-$(call dist-for-goals,dist_files sdk win_sdk,$(LOCAL_BUILT_MODULE))
-ifdef HOST_CROSS_OS
-# Archive adb.exe for win_sdk build.
-$(call dist-for-goals,win_sdk,$(ALL_MODULES.host_cross_adb.BUILT))
-endif
-
-
-# adbd device daemon
-# =========================================================
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := \
- daemon/main.cpp \
- daemon/mdns.cpp \
- services.cpp \
- file_sync_service.cpp \
- framebuffer_service.cpp \
- remount_service.cpp \
- set_verity_enable_state_service.cpp \
- shell_service.cpp \
- shell_service_protocol.cpp \
-
-LOCAL_CFLAGS := \
- $(ADB_COMMON_CFLAGS) \
- $(ADB_COMMON_linux_CFLAGS) \
- -DADB_HOST=0 \
- -D_GNU_SOURCE \
- -Wno-deprecated-declarations \
-
-LOCAL_CFLAGS += -DALLOW_ADBD_NO_AUTH=$(if $(filter userdebug eng,$(TARGET_BUILD_VARIANT)),1,0)
-
-ifneq (,$(filter userdebug eng,$(TARGET_BUILD_VARIANT)))
-LOCAL_CFLAGS += -DALLOW_ADBD_DISABLE_VERITY=1
-LOCAL_CFLAGS += -DALLOW_ADBD_ROOT=1
-endif
-
-LOCAL_MODULE := adbd
-
-LOCAL_FORCE_STATIC_EXECUTABLE := true
-
-LOCAL_SANITIZE := $(adb_target_sanitize)
-LOCAL_STRIP_MODULE := keep_symbols
-LOCAL_STATIC_LIBRARIES := \
- libadbd \
- libasyncio \
- libavb_user \
- libbase \
- libqemu_pipe \
- libbootloader_message \
- libfs_mgr \
- libfec \
- libfec_rs \
- libselinux \
- liblog \
- libext4_utils \
- libsquashfs_utils \
- libcutils \
- libbase \
- libcrypto_utils \
- libcrypto \
- libminijail \
- libmdnssd \
- libdebuggerd_handler \
-
-include $(BUILD_EXECUTABLE)
-
-# adb integration test
-# =========================================================
-$(call dist-for-goals,sdk,$(ALL_MODULES.adb_integration_test_adb.BUILT))
-$(call dist-for-goals,sdk,$(ALL_MODULES.adb_integration_test_device.BUILT))
-
-include $(call first-makefiles-under,$(LOCAL_PATH))
diff --git a/adb/CPPLINT.cfg b/adb/CPPLINT.cfg
deleted file mode 100644
index f496490..0000000
--- a/adb/CPPLINT.cfg
+++ /dev/null
@@ -1,2 +0,0 @@
-set noparent
-filter=-build/header_guard,-build/include,-readability/function,-whitespace/indent
diff --git a/adb/adb.cpp b/adb/adb.cpp
index c4df5c4..65fa2e7 100644
--- a/adb/adb.cpp
+++ b/adb/adb.cpp
@@ -44,6 +44,7 @@
#include <android-base/parsenetaddress.h>
#include <android-base/stringprintf.h>
#include <android-base/strings.h>
+#include <build/version.h>
#include "adb_auth.h"
#include "adb_io.h"
@@ -66,8 +67,8 @@
"Android Debug Bridge version %d.%d.%d\n"
"Version %s\n"
"Installed as %s\n",
- ADB_VERSION_MAJOR, ADB_VERSION_MINOR, ADB_SERVER_VERSION, ADB_VERSION,
- android::base::GetExecutablePath().c_str());
+ ADB_VERSION_MAJOR, ADB_VERSION_MINOR, ADB_SERVER_VERSION,
+ android::build::GetBuildNumber().c_str(), android::base::GetExecutablePath().c_str());
}
void fatal(const char *fmt, ...) {
@@ -135,8 +136,16 @@
void handle_offline(atransport *t)
{
- D("adb: offline");
- //Close the associated usb
+ if (t->GetConnectionState() == kCsOffline) {
+ LOG(INFO) << t->serial_name() << ": already offline";
+ return;
+ }
+
+ LOG(INFO) << t->serial_name() << ": offline";
+
+ t->SetConnectionState(kCsOffline);
+
+ // Close the associated usb
t->online = 0;
// This is necessary to avoid a race condition that occurred when a transport closes
@@ -317,10 +326,7 @@
}
static void handle_new_connection(atransport* t, apacket* p) {
- if (t->GetConnectionState() != kCsOffline) {
- t->SetConnectionState(kCsOffline);
- handle_offline(t);
- }
+ handle_offline(t);
t->update_version(p->msg.arg0, p->msg.arg1);
parse_banner(p->payload, t);
@@ -349,19 +355,6 @@
CHECK_EQ(p->payload.size(), p->msg.data_length);
switch(p->msg.command){
- case A_SYNC:
- if (p->msg.arg0){
- send_packet(p, t);
-#if ADB_HOST
- send_connect(t);
-#endif
- } else {
- t->SetConnectionState(kCsOffline);
- handle_offline(t);
- send_packet(p, t);
- }
- return;
-
case A_CNXN: // CONNECT(version, maxdata, "system-id-string")
handle_new_connection(t, p);
break;
diff --git a/adb/adb_client.cpp b/adb/client/adb_client.cpp
similarity index 100%
rename from adb/adb_client.cpp
rename to adb/client/adb_client.cpp
diff --git a/adb/adb_client.h b/adb/client/adb_client.h
similarity index 100%
rename from adb/adb_client.h
rename to adb/client/adb_client.h
diff --git a/adb/adb_auth_host.cpp b/adb/client/auth.cpp
similarity index 100%
rename from adb/adb_auth_host.cpp
rename to adb/client/auth.cpp
diff --git a/adb/bugreport.cpp b/adb/client/bugreport.cpp
similarity index 100%
rename from adb/bugreport.cpp
rename to adb/client/bugreport.cpp
diff --git a/adb/bugreport.h b/adb/client/bugreport.h
similarity index 100%
rename from adb/bugreport.h
rename to adb/client/bugreport.h
diff --git a/adb/commandline.cpp b/adb/client/commandline.cpp
similarity index 100%
rename from adb/commandline.cpp
rename to adb/client/commandline.cpp
diff --git a/adb/commandline.h b/adb/client/commandline.h
similarity index 100%
rename from adb/commandline.h
rename to adb/client/commandline.h
diff --git a/adb/console.cpp b/adb/client/console.cpp
similarity index 100%
rename from adb/console.cpp
rename to adb/client/console.cpp
diff --git a/adb/file_sync_client.cpp b/adb/client/file_sync_client.cpp
similarity index 100%
rename from adb/file_sync_client.cpp
rename to adb/client/file_sync_client.cpp
diff --git a/adb/line_printer.cpp b/adb/client/line_printer.cpp
similarity index 100%
rename from adb/line_printer.cpp
rename to adb/client/line_printer.cpp
diff --git a/adb/line_printer.h b/adb/client/line_printer.h
similarity index 100%
rename from adb/line_printer.h
rename to adb/client/line_printer.h
diff --git a/adb/transport_mdns.cpp b/adb/client/transport_mdns.cpp
similarity index 100%
rename from adb/transport_mdns.cpp
rename to adb/client/transport_mdns.cpp
diff --git a/adb/adbd_auth.cpp b/adb/daemon/auth.cpp
similarity index 100%
rename from adb/adbd_auth.cpp
rename to adb/daemon/auth.cpp
diff --git a/adb/file_sync_service.cpp b/adb/daemon/file_sync_service.cpp
similarity index 100%
rename from adb/file_sync_service.cpp
rename to adb/daemon/file_sync_service.cpp
diff --git a/adb/framebuffer_service.cpp b/adb/daemon/framebuffer_service.cpp
similarity index 100%
rename from adb/framebuffer_service.cpp
rename to adb/daemon/framebuffer_service.cpp
diff --git a/adb/jdwp_service.cpp b/adb/daemon/jdwp_service.cpp
similarity index 98%
rename from adb/jdwp_service.cpp
rename to adb/daemon/jdwp_service.cpp
index 6f5396a..9761558 100644
--- a/adb/jdwp_service.cpp
+++ b/adb/daemon/jdwp_service.cpp
@@ -128,7 +128,7 @@
static void jdwp_process_list_updated(void);
struct JdwpProcess;
-static std::list<std::unique_ptr<JdwpProcess>> _jdwp_list;
+static auto& _jdwp_list = *new std::list<std::unique_ptr<JdwpProcess>>();
struct JdwpProcess {
explicit JdwpProcess(int socket) {
@@ -511,7 +511,7 @@
bool need_initial;
};
-static std::vector<std::unique_ptr<JdwpTracker>> _jdwp_trackers;
+static auto& _jdwp_trackers = *new std::vector<std::unique_ptr<JdwpTracker>>();
static void jdwp_process_list_updated(void) {
std::string data;
diff --git a/adb/daemon/main.cpp b/adb/daemon/main.cpp
index 3c27582..4314dae 100644
--- a/adb/daemon/main.cpp
+++ b/adb/daemon/main.cpp
@@ -158,9 +158,10 @@
// descriptor will always be open.
adbd_cloexec_auth_socket();
- if (ALLOW_ADBD_NO_AUTH && !android::base::GetBoolProperty("ro.adb.secure", false)) {
- auth_required = false;
- }
+#if defined(ALLOW_ADBD_NO_AUTH)
+ // If ro.adb.secure is unset, default to no authentication required.
+ auth_required = android::base::GetBoolProperty("ro.adb.secure", false);
+#endif
adbd_auth_init();
diff --git a/adb/remount_service.cpp b/adb/daemon/remount_service.cpp
similarity index 100%
rename from adb/remount_service.cpp
rename to adb/daemon/remount_service.cpp
diff --git a/adb/set_verity_enable_state_service.cpp b/adb/daemon/set_verity_enable_state_service.cpp
similarity index 100%
rename from adb/set_verity_enable_state_service.cpp
rename to adb/daemon/set_verity_enable_state_service.cpp
diff --git a/adb/shell_service.cpp b/adb/daemon/shell_service.cpp
similarity index 100%
rename from adb/shell_service.cpp
rename to adb/daemon/shell_service.cpp
diff --git a/adb/shell_service_test.cpp b/adb/daemon/shell_service_test.cpp
similarity index 100%
rename from adb/shell_service_test.cpp
rename to adb/daemon/shell_service_test.cpp
diff --git a/adb/daemon/usb.cpp b/adb/daemon/usb.cpp
index 87ed3db..20fb6a3 100644
--- a/adb/daemon/usb.cpp
+++ b/adb/daemon/usb.cpp
@@ -317,6 +317,8 @@
goto err;
}
+ memset(&h->read_aiob.ctx, 0, sizeof(h->read_aiob.ctx));
+ memset(&h->write_aiob.ctx, 0, sizeof(h->write_aiob.ctx));
if (io_setup(USB_FFS_NUM_BUFS, &h->read_aiob.ctx) ||
io_setup(USB_FFS_NUM_BUFS, &h->write_aiob.ctx)) {
D("[ aio: got error on io_setup (%d) ]", errno);
diff --git a/adb/protocol.txt b/adb/protocol.txt
index 55ea87f..f4523c4 100644
--- a/adb/protocol.txt
+++ b/adb/protocol.txt
@@ -183,9 +183,11 @@
Command constant: A_SYNC
-The SYNC message is used by the io pump to make sure that stale
+*** obsolete, no longer used ***
+
+The SYNC message was used by the io pump to make sure that stale
outbound messages are discarded when the connection to the remote side
-is broken. It is only used internally to the bridge and never valid
+is broken. It was only used internally to the bridge and never valid
to send across the wire.
* when the connection to the remote side goes offline, the io pump
diff --git a/adb/transport.cpp b/adb/transport.cpp
index 6b1a00b..3329f0f 100644
--- a/adb/transport.cpp
+++ b/adb/transport.cpp
@@ -28,6 +28,7 @@
#include <unistd.h>
#include <algorithm>
+#include <deque>
#include <list>
#include <mutex>
#include <thread>
@@ -38,12 +39,13 @@
#include <android-base/strings.h>
#include <android-base/thread_annotations.h>
+#include <diagnose_usb.h>
+
#include "adb.h"
#include "adb_auth.h"
#include "adb_io.h"
#include "adb_trace.h"
#include "adb_utils.h"
-#include "diagnose_usb.h"
#include "fdevent.h"
static void transport_unref(atransport *t);
@@ -65,6 +67,82 @@
return next++;
}
+BlockingConnectionAdapter::BlockingConnectionAdapter(std::unique_ptr<BlockingConnection> connection)
+ : underlying_(std::move(connection)) {}
+
+BlockingConnectionAdapter::~BlockingConnectionAdapter() {
+ LOG(INFO) << "BlockingConnectionAdapter(" << this->transport_name_ << "): destructing";
+ Stop();
+}
+
+void BlockingConnectionAdapter::Start() {
+ read_thread_ = std::thread([this]() {
+ LOG(INFO) << this->transport_name_ << ": read thread spawning";
+ while (true) {
+ std::unique_ptr<apacket> packet(new apacket());
+ if (!underlying_->Read(packet.get())) {
+ PLOG(INFO) << this->transport_name_ << ": read failed";
+ break;
+ }
+ read_callback_(this, std::move(packet));
+ }
+ std::call_once(this->error_flag_, [this]() { this->error_callback_(this, "read failed"); });
+ });
+
+ write_thread_ = std::thread([this]() {
+ LOG(INFO) << this->transport_name_ << ": write thread spawning";
+ while (true) {
+ std::unique_lock<std::mutex> lock(mutex_);
+ cv_.wait(lock, [this]() { return this->stopped_ || !this->write_queue_.empty(); });
+
+ if (this->stopped_) {
+ return;
+ }
+
+ std::unique_ptr<apacket> packet = std::move(this->write_queue_.front());
+ this->write_queue_.pop_front();
+ lock.unlock();
+
+ if (!this->underlying_->Write(packet.get())) {
+ break;
+ }
+ }
+ std::call_once(this->error_flag_, [this]() { this->error_callback_(this, "write failed"); });
+ });
+}
+
+void BlockingConnectionAdapter::Stop() {
+ std::unique_lock<std::mutex> lock(mutex_);
+ if (stopped_) {
+ LOG(INFO) << "BlockingConnectionAdapter(" << this->transport_name_ << "): already stopped";
+ return;
+ }
+
+ stopped_ = true;
+ lock.unlock();
+
+ LOG(INFO) << "BlockingConnectionAdapter(" << this->transport_name_ << "): stopping";
+
+ this->underlying_->Close();
+
+ this->cv_.notify_one();
+ read_thread_.join();
+ write_thread_.join();
+
+ LOG(INFO) << "BlockingConnectionAdapter(" << this->transport_name_ << "): stopped";
+ std::call_once(this->error_flag_, [this]() { this->error_callback_(this, "requested stop"); });
+}
+
+bool BlockingConnectionAdapter::Write(std::unique_ptr<apacket> packet) {
+ {
+ std::unique_lock<std::mutex> lock(this->mutex_);
+ write_queue_.emplace_back(std::move(packet));
+ }
+
+ cv_.notify_one();
+ return true;
+}
+
bool FdConnection::Read(apacket* packet) {
if (!ReadFdExactly(fd_.get(), &packet->msg, sizeof(amessage))) {
D("remote local: read terminated (message)");
@@ -143,67 +221,6 @@
return result;
}
-static int read_packet(int fd, const char* name, apacket** ppacket) {
- ATRACE_NAME("read_packet");
- char buff[8];
- if (!name) {
- snprintf(buff, sizeof buff, "fd=%d", fd);
- name = buff;
- }
- char* p = reinterpret_cast<char*>(ppacket); /* really read a packet address */
- int len = sizeof(apacket*);
- while (len > 0) {
- int r = adb_read(fd, p, len);
- if (r > 0) {
- len -= r;
- p += r;
- } else {
- D("%s: read_packet (fd=%d), error ret=%d: %s", name, fd, r, strerror(errno));
- return -1;
- }
- }
-
- VLOG(TRANSPORT) << dump_packet(name, "from remote", *ppacket);
- return 0;
-}
-
-static int write_packet(int fd, const char* name, apacket** ppacket) {
- ATRACE_NAME("write_packet");
- char buff[8];
- if (!name) {
- snprintf(buff, sizeof buff, "fd=%d", fd);
- name = buff;
- }
- VLOG(TRANSPORT) << dump_packet(name, "to remote", *ppacket);
- char* p = reinterpret_cast<char*>(ppacket); /* we really write the packet address */
- int len = sizeof(apacket*);
- while (len > 0) {
- int r = adb_write(fd, p, len);
- if (r > 0) {
- len -= r;
- p += r;
- } else {
- D("%s: write_packet (fd=%d) error ret=%d: %s", name, fd, r, strerror(errno));
- return -1;
- }
- }
- return 0;
-}
-
-static void transport_socket_events(int fd, unsigned events, void* _t) {
- atransport* t = reinterpret_cast<atransport*>(_t);
- D("transport_socket_events(fd=%d, events=%04x,...)", fd, events);
- if (events & FDE_READ) {
- apacket* p = 0;
- if (read_packet(fd, t->serial, &p)) {
- D("%s: failed to read packet from transport socket on fd %d", t->serial, fd);
- return;
- }
-
- handle_packet(p, (atransport*)_t);
- }
-}
-
void send_packet(apacket* p, atransport* t) {
p->msg.magic = p->msg.command ^ 0xffffffff;
// compute a checksum for connection/auth packets for compatibility reasons
@@ -213,162 +230,18 @@
p->msg.data_check = calculate_apacket_checksum(p);
}
- print_packet("send", p);
+ VLOG(TRANSPORT) << dump_packet(t->serial, "to remote", p);
if (t == NULL) {
fatal("Transport is null");
}
- if (write_packet(t->transport_socket, t->serial, &p)) {
- fatal_errno("cannot enqueue packet on transport socket");
+ if (t->Write(p) != 0) {
+ D("%s: failed to enqueue packet, closing transport", t->serial);
+ t->Kick();
}
}
-// The transport is opened by transport_register_func before
-// the read_transport and write_transport threads are started.
-//
-// The read_transport thread issues a SYNC(1, token) message to let
-// the write_transport thread know to start things up. In the event
-// of transport IO failure, the read_transport thread will post a
-// SYNC(0,0) message to ensure shutdown.
-//
-// The transport will not actually be closed until both threads exit, but the threads
-// will kick the transport on their way out to disconnect the underlying device.
-//
-// read_transport thread reads data from a transport (representing a usb/tcp connection),
-// and makes the main thread call handle_packet().
-static void read_transport_thread(void* _t) {
- atransport* t = reinterpret_cast<atransport*>(_t);
- apacket* p;
-
- adb_thread_setname(
- android::base::StringPrintf("<-%s", (t->serial != nullptr ? t->serial : "transport")));
- D("%s: starting read_transport thread on fd %d, SYNC online (%d)", t->serial, t->fd,
- t->sync_token + 1);
- p = get_apacket();
- p->msg.command = A_SYNC;
- p->msg.arg0 = 1;
- p->msg.arg1 = ++(t->sync_token);
- p->msg.magic = A_SYNC ^ 0xffffffff;
- D("sending SYNC packet (len = %u, payload.size() = %zu)", p->msg.data_length, p->payload.size());
- if (write_packet(t->fd, t->serial, &p)) {
- put_apacket(p);
- D("%s: failed to write SYNC packet", t->serial);
- goto oops;
- }
-
- D("%s: data pump started", t->serial);
- for (;;) {
- ATRACE_NAME("read_transport loop");
- p = get_apacket();
-
- {
- ATRACE_NAME("read_transport read_remote");
- if (!t->connection->Read(p)) {
- D("%s: remote read failed for transport", t->serial);
- put_apacket(p);
- break;
- }
-
- if (!check_header(p, t)) {
- D("%s: remote read: bad header", t->serial);
- put_apacket(p);
- break;
- }
-
-#if ADB_HOST
- if (p->msg.command == 0) {
- put_apacket(p);
- continue;
- }
-#endif
- }
-
- D("%s: received remote packet, sending to transport", t->serial);
- if (write_packet(t->fd, t->serial, &p)) {
- put_apacket(p);
- D("%s: failed to write apacket to transport", t->serial);
- goto oops;
- }
- }
-
- D("%s: SYNC offline for transport", t->serial);
- p = get_apacket();
- p->msg.command = A_SYNC;
- p->msg.arg0 = 0;
- p->msg.arg1 = 0;
- p->msg.magic = A_SYNC ^ 0xffffffff;
- if (write_packet(t->fd, t->serial, &p)) {
- put_apacket(p);
- D("%s: failed to write SYNC apacket to transport", t->serial);
- }
-
-oops:
- D("%s: read_transport thread is exiting", t->serial);
- kick_transport(t);
- transport_unref(t);
-}
-
-// write_transport thread gets packets sent by the main thread (through send_packet()),
-// and writes to a transport (representing a usb/tcp connection).
-static void write_transport_thread(void* _t) {
- atransport* t = reinterpret_cast<atransport*>(_t);
- apacket* p;
- int active = 0;
-
- adb_thread_setname(
- android::base::StringPrintf("->%s", (t->serial != nullptr ? t->serial : "transport")));
- D("%s: starting write_transport thread, reading from fd %d", t->serial, t->fd);
-
- for (;;) {
- ATRACE_NAME("write_transport loop");
- if (read_packet(t->fd, t->serial, &p)) {
- D("%s: failed to read apacket from transport on fd %d", t->serial, t->fd);
- break;
- }
-
- if (p->msg.command == A_SYNC) {
- if (p->msg.arg0 == 0) {
- D("%s: transport SYNC offline", t->serial);
- put_apacket(p);
- break;
- } else {
- if (p->msg.arg1 == t->sync_token) {
- D("%s: transport SYNC online", t->serial);
- active = 1;
- } else {
- D("%s: transport ignoring SYNC %d != %d", t->serial, p->msg.arg1, t->sync_token);
- }
- }
- } else {
- if (active) {
- D("%s: transport got packet, sending to remote", t->serial);
- ATRACE_NAME("write_transport write_remote");
-
- // Allow sending the payload's implicit null terminator.
- if (p->msg.data_length != p->payload.size()) {
- LOG(FATAL) << "packet data length doesn't match payload: msg.data_length = "
- << p->msg.data_length << ", payload.size() = " << p->payload.size();
- }
-
- if (t->Write(p) != 0) {
- D("%s: remote write failed for transport", t->serial);
- put_apacket(p);
- break;
- }
- } else {
- D("%s: transport ignoring packet while offline", t->serial);
- }
- }
-
- put_apacket(p);
- }
-
- D("%s: write_transport thread is exiting, fd %d", t->serial, t->fd);
- kick_transport(t);
- transport_unref(t);
-}
-
void kick_transport(atransport* t) {
std::lock_guard<std::recursive_mutex> lock(transport_lock);
// As kick_transport() can be called from threads without guarantee that t is valid,
@@ -559,9 +432,10 @@
return 0;
}
-static void transport_registration_func(int _fd, unsigned ev, void* data) {
+static void remove_transport(atransport*);
+
+static void transport_registration_func(int _fd, unsigned ev, void*) {
tmsg m;
- int s[2];
atransport* t;
if (!(ev & FDE_READ)) {
@@ -575,13 +449,7 @@
t = m.transport;
if (m.action == 0) {
- D("transport: %s removing and free'ing %d", t->serial, t->transport_socket);
-
- /* IMPORTANT: the remove closes one half of the
- ** socket pair. The close closes the other half.
- */
- fdevent_remove(&(t->transport_fde));
- adb_close(t->fd);
+ D("transport: %s deleting", t->serial);
{
std::lock_guard<std::recursive_mutex> lock(transport_lock);
@@ -603,23 +471,33 @@
/* don't create transport threads for inaccessible devices */
if (t->GetConnectionState() != kCsNoPerm) {
/* initial references are the two threads */
- t->ref_count = 2;
+ t->ref_count = 1;
+ t->connection->SetTransportName(t->serial_name());
+ t->connection->SetReadCallback([t](Connection*, std::unique_ptr<apacket> p) {
+ if (!check_header(p.get(), t)) {
+ D("%s: remote read: bad header", t->serial);
+ return false;
+ }
- if (adb_socketpair(s)) {
- fatal_errno("cannot open transport socketpair");
- }
+ VLOG(TRANSPORT) << dump_packet(t->serial, "from remote", p.get());
+ apacket* packet = p.release();
- D("transport: %s socketpair: (%d,%d) starting", t->serial, s[0], s[1]);
+ // TODO: Does this need to run on the main thread?
+ fdevent_run_on_main_thread([packet, t]() { handle_packet(packet, t); });
+ return true;
+ });
+ t->connection->SetErrorCallback([t](Connection*, const std::string& error) {
+ D("%s: connection terminated: %s", t->serial, error.c_str());
+ fdevent_run_on_main_thread([t]() {
+ handle_offline(t);
+ transport_unref(t);
+ });
+ });
- t->transport_socket = s[0];
- t->fd = s[1];
-
- fdevent_install(&(t->transport_fde), t->transport_socket, transport_socket_events, t);
-
- fdevent_set(&(t->transport_fde), FDE_READ);
-
- std::thread(write_transport_thread, t).detach();
- std::thread(read_transport_thread, t).detach();
+ t->connection->Start();
+#if ADB_HOST
+ send_connect(t);
+#endif
}
{
@@ -685,7 +563,7 @@
t->ref_count--;
if (t->ref_count == 0) {
D("transport: %s unref (kicking and closing)", t->serial);
- t->connection->Close();
+ t->connection->Stop();
remove_transport(t);
} else {
D("transport: %s unref (count=%zu)", t->serial, t->ref_count);
@@ -736,9 +614,7 @@
std::unique_lock<std::recursive_mutex> lock(transport_lock);
for (const auto& t : transport_list) {
if (t->GetConnectionState() == kCsNoPerm) {
-#if ADB_HOST
*error_out = UsbNoPermissionsLongHelpText();
-#endif
continue;
}
@@ -813,14 +689,14 @@
}
int atransport::Write(apacket* p) {
- return this->connection->Write(p) ? 0 : -1;
+ return this->connection->Write(std::unique_ptr<apacket>(p)) ? 0 : -1;
}
void atransport::Kick() {
if (!kicked_) {
D("kicking transport %s", this->serial);
kicked_ = true;
- this->connection->Close();
+ this->connection->Stop();
}
}
@@ -833,7 +709,7 @@
connection_state_ = state;
}
-const std::string atransport::connection_state_name() const {
+std::string atransport::connection_state_name() const {
ConnectionState state = GetConnectionState();
switch (state) {
case kCsOffline:
diff --git a/adb/transport.h b/adb/transport.h
index 9700f44..8b71e34 100644
--- a/adb/transport.h
+++ b/adb/transport.h
@@ -20,12 +20,14 @@
#include <sys/types.h>
#include <atomic>
+#include <condition_variable>
#include <deque>
#include <functional>
#include <list>
#include <memory>
#include <mutex>
#include <string>
+#include <thread>
#include <unordered_set>
#include <openssl/rsa.h>
@@ -57,15 +59,47 @@
TransportId NextTransportId();
-// Abstraction for a blocking packet transport.
+// Abstraction for a non-blocking packet transport.
struct Connection {
Connection() = default;
- Connection(const Connection& copy) = delete;
- Connection(Connection&& move) = delete;
-
- // Destroy a Connection. Formerly known as 'Close' in atransport.
virtual ~Connection() = default;
+ void SetTransportName(std::string transport_name) {
+ transport_name_ = std::move(transport_name);
+ }
+
+ using ReadCallback = std::function<bool(Connection*, std::unique_ptr<apacket>)>;
+ void SetReadCallback(ReadCallback callback) {
+ CHECK(!read_callback_);
+ read_callback_ = callback;
+ }
+
+ // Called after the Connection has terminated, either by an error or because Stop was called.
+ using ErrorCallback = std::function<void(Connection*, const std::string&)>;
+ void SetErrorCallback(ErrorCallback callback) {
+ CHECK(!error_callback_);
+ error_callback_ = callback;
+ }
+
+ virtual bool Write(std::unique_ptr<apacket> packet) = 0;
+
+ virtual void Start() = 0;
+ virtual void Stop() = 0;
+
+ std::string transport_name_;
+ ReadCallback read_callback_;
+ ErrorCallback error_callback_;
+};
+
+// Abstraction for a blocking packet transport.
+struct BlockingConnection {
+ BlockingConnection() = default;
+ BlockingConnection(const BlockingConnection& copy) = delete;
+ BlockingConnection(BlockingConnection&& move) = delete;
+
+ // Destroy a BlockingConnection. Formerly known as 'Close' in atransport.
+ virtual ~BlockingConnection() = default;
+
// Read/Write a packet. These functions are concurrently called from a transport's reader/writer
// threads.
virtual bool Read(apacket* packet) = 0;
@@ -77,7 +111,30 @@
virtual void Close() = 0;
};
-struct FdConnection : public Connection {
+struct BlockingConnectionAdapter : public Connection {
+ explicit BlockingConnectionAdapter(std::unique_ptr<BlockingConnection> connection);
+
+ virtual ~BlockingConnectionAdapter();
+
+ virtual bool Write(std::unique_ptr<apacket> packet) override final;
+
+ virtual void Start() override final;
+ virtual void Stop() override final;
+
+ bool stopped_ = false;
+
+ std::unique_ptr<BlockingConnection> underlying_;
+ std::thread read_thread_;
+ std::thread write_thread_;
+
+ std::deque<std::unique_ptr<apacket>> write_queue_;
+ std::mutex mutex_;
+ std::condition_variable cv_;
+
+ std::once_flag error_flag_;
+};
+
+struct FdConnection : public BlockingConnection {
explicit FdConnection(unique_fd fd) : fd_(std::move(fd)) {}
bool Read(apacket* packet) override final;
@@ -89,7 +146,7 @@
unique_fd fd_;
};
-struct UsbConnection : public Connection {
+struct UsbConnection : public BlockingConnection {
explicit UsbConnection(usb_handle* handle) : handle_(handle) {}
~UsbConnection();
@@ -110,7 +167,6 @@
atransport(ConnectionState state = kCsOffline)
: id(NextTransportId()), connection_state_(state) {
- transport_fde = {};
// Initialize protocol to min version for compatibility with older versions.
// Version will be updated post-connect.
protocol_version = A_VERSION_MIN;
@@ -126,11 +182,7 @@
void SetConnectionState(ConnectionState state);
const TransportId id;
- int fd = -1;
- int transport_socket = -1;
- fdevent transport_fde;
size_t ref_count = 0;
- uint32_t sync_token = 0;
bool online = false;
TransportType type = kTransportAny;
@@ -152,8 +204,8 @@
char token[TOKEN_SIZE] = {};
size_t failed_auth_attempts = 0;
- const std::string serial_name() const { return serial ? serial : "<unknown>"; }
- const std::string connection_state_name() const;
+ std::string serial_name() const { return serial ? serial : "<unknown>"; }
+ std::string connection_state_name() const;
void update_version(int version, size_t payload);
int get_protocol_version() const;
diff --git a/adb/transport_local.cpp b/adb/transport_local.cpp
index 560a031..ff395dc 100644
--- a/adb/transport_local.cpp
+++ b/adb/transport_local.cpp
@@ -445,13 +445,14 @@
int fail = 0;
unique_fd fd(s);
- t->sync_token = 1;
t->type = kTransportLocal;
#if ADB_HOST
// Emulator connection.
if (local) {
- t->connection.reset(new EmulatorConnection(std::move(fd), adb_port));
+ std::unique_ptr<BlockingConnection> emulator_connection(
+ new EmulatorConnection(std::move(fd), adb_port));
+ t->connection.reset(new BlockingConnectionAdapter(std::move(emulator_connection)));
std::lock_guard<std::mutex> lock(local_transports_lock);
atransport* existing_transport = find_emulator_transport_by_adb_port_locked(adb_port);
if (existing_transport != NULL) {
@@ -470,6 +471,7 @@
#endif
// Regular tcp connection.
- t->connection.reset(new FdConnection(std::move(fd)));
+ std::unique_ptr<BlockingConnection> fd_connection(new FdConnection(std::move(fd)));
+ t->connection.reset(new BlockingConnectionAdapter(std::move(fd_connection)));
return fail;
}
diff --git a/adb/transport_mdns_unsupported.cpp b/adb/transport_mdns_unsupported.cpp
deleted file mode 100644
index 387d341..0000000
--- a/adb/transport_mdns_unsupported.cpp
+++ /dev/null
@@ -1,18 +0,0 @@
-/*
- * Copyright (C) 2016 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.
- */
-
-/* For when mDNS discovery is unsupported */
-void init_mdns_transport_discovery(void) {}
diff --git a/adb/transport_usb.cpp b/adb/transport_usb.cpp
index d7565f6..33e00a1 100644
--- a/adb/transport_usb.cpp
+++ b/adb/transport_usb.cpp
@@ -174,8 +174,8 @@
void init_usb_transport(atransport* t, usb_handle* h) {
D("transport: usb");
- t->connection.reset(new UsbConnection(h));
- t->sync_token = 1;
+ std::unique_ptr<BlockingConnection> connection(new UsbConnection(h));
+ t->connection.reset(new BlockingConnectionAdapter(std::move(connection)));
t->type = kTransportUsb;
}
diff --git a/base/include/android-base/logging.h b/base/include/android-base/logging.h
index afff2c9..cc7aaf6 100644
--- a/base/include/android-base/logging.h
+++ b/base/include/android-base/logging.h
@@ -105,6 +105,9 @@
void DefaultAborter(const char* abort_message);
+std::string GetDefaultTag();
+void SetDefaultTag(const std::string& tag);
+
#ifdef __ANDROID__
// We expose this even though it is the default because a user that wants to
// override the default log buffer will have to construct this themselves.
diff --git a/base/logging.cpp b/base/logging.cpp
index 1f7bc2a..a31feef 100644
--- a/base/logging.cpp
+++ b/base/logging.cpp
@@ -139,9 +139,27 @@
return aborter;
}
-static std::string& ProgramInvocationName() {
- static auto& programInvocationName = *new std::string(getprogname());
- return programInvocationName;
+static std::recursive_mutex& TagLock() {
+ static auto& tag_lock = *new std::recursive_mutex();
+ return tag_lock;
+}
+static std::string* gDefaultTag;
+std::string GetDefaultTag() {
+ std::lock_guard<std::recursive_mutex> lock(TagLock());
+ if (gDefaultTag == nullptr) {
+ return "";
+ }
+ return *gDefaultTag;
+}
+void SetDefaultTag(const std::string& tag) {
+ std::lock_guard<std::recursive_mutex> lock(TagLock());
+ if (gDefaultTag != nullptr) {
+ delete gDefaultTag;
+ gDefaultTag = nullptr;
+ }
+ if (!tag.empty()) {
+ gDefaultTag = new std::string(tag);
+ }
}
static bool gInitialized = false;
@@ -269,8 +287,7 @@
// Linux to recover this, but we don't have that luxury on the Mac/Windows,
// and there are a couple of argv[0] variants that are commonly used.
if (argv != nullptr) {
- std::lock_guard<std::mutex> lock(LoggingLock());
- ProgramInvocationName() = basename(argv[0]);
+ SetDefaultTag(basename(argv[0]));
}
const char* tags = getenv("ANDROID_LOG_TAGS");
@@ -448,8 +465,15 @@
void LogMessage::LogLine(const char* file, unsigned int line, LogId id, LogSeverity severity,
const char* tag, const char* message) {
- if (tag == nullptr) tag = ProgramInvocationName().c_str();
- Logger()(id, severity, tag, file, line, message);
+ if (tag == nullptr) {
+ std::lock_guard<std::recursive_mutex> lock(TagLock());
+ if (gDefaultTag == nullptr) {
+ gDefaultTag = new std::string(getprogname());
+ }
+ Logger()(id, severity, gDefaultTag->c_str(), file, line, message);
+ } else {
+ Logger()(id, severity, tag, file, line, message);
+ }
}
void LogMessage::LogLine(const char* file, unsigned int line, LogId id, LogSeverity severity,
diff --git a/base/logging_test.cpp b/base/logging_test.cpp
index 6f05d9b..5f689fa 100644
--- a/base/logging_test.cpp
+++ b/base/logging_test.cpp
@@ -206,8 +206,8 @@
}
#endif
-static void CheckMessage(const CapturedStderr& cap,
- android::base::LogSeverity severity, const char* expected) {
+static void CheckMessage(const CapturedStderr& cap, android::base::LogSeverity severity,
+ const char* expected, const char* expected_tag = nullptr) {
std::string output;
ASSERT_EQ(0, lseek(cap.fd(), 0, SEEK_SET));
android::base::ReadFdToString(cap.fd(), &output);
@@ -217,9 +217,18 @@
// many characters are in the log message.
ASSERT_GT(output.length(), strlen(expected));
ASSERT_NE(nullptr, strstr(output.c_str(), expected)) << output;
+ if (expected_tag != nullptr) {
+ ASSERT_NE(nullptr, strstr(output.c_str(), expected_tag)) << output;
+ }
#if !defined(_WIN32)
- std::regex message_regex(make_log_pattern(severity, expected));
+ std::string regex_str;
+ if (expected_tag != nullptr) {
+ regex_str.append(expected_tag);
+ regex_str.append(" ");
+ }
+ regex_str.append(make_log_pattern(severity, expected));
+ std::regex message_regex(regex_str);
ASSERT_TRUE(std::regex_search(output, message_regex)) << output;
#endif
}
@@ -600,3 +609,17 @@
__attribute__((constructor)) void TestLoggingInConstructor() {
LOG(ERROR) << "foobar";
}
+
+TEST(logging, SetDefaultTag) {
+ constexpr const char* expected_tag = "test_tag";
+ constexpr const char* expected_msg = "foobar";
+ CapturedStderr cap;
+ {
+ std::string old_default_tag = android::base::GetDefaultTag();
+ android::base::SetDefaultTag(expected_tag);
+ android::base::ScopedLogSeverity sls(android::base::LogSeverity::INFO);
+ LOG(INFO) << expected_msg;
+ android::base::SetDefaultTag(old_default_tag);
+ }
+ CheckMessage(cap, android::base::LogSeverity::INFO, expected_msg, expected_tag);
+}
diff --git a/diagnose_usb/Android.bp b/diagnose_usb/Android.bp
new file mode 100644
index 0000000..a7ecf37
--- /dev/null
+++ b/diagnose_usb/Android.bp
@@ -0,0 +1,13 @@
+cc_library_static {
+ name: "libdiagnose_usb",
+ cflags: ["-Wall", "-Wextra", "-Werror"],
+ host_supported: true,
+ target: {
+ windows: {
+ enabled: true,
+ },
+ },
+ srcs: ["diagnose_usb.cpp"],
+ export_include_dirs: ["include"],
+ static_libs: ["libbase"],
+}
diff --git a/diagnose_usb/OWNERS b/diagnose_usb/OWNERS
new file mode 100644
index 0000000..643b448
--- /dev/null
+++ b/diagnose_usb/OWNERS
@@ -0,0 +1,2 @@
+jmgao@google.com
+yabinc@google.com
diff --git a/adb/diagnose_usb.cpp b/diagnose_usb/diagnose_usb.cpp
similarity index 97%
rename from adb/diagnose_usb.cpp
rename to diagnose_usb/diagnose_usb.cpp
index 9f721bf..5695ece 100644
--- a/adb/diagnose_usb.cpp
+++ b/diagnose_usb/diagnose_usb.cpp
@@ -33,7 +33,7 @@
// Returns a message describing any potential problems we find with udev, or an empty string if we
// can't find plugdev information (i.e. udev is not installed).
static std::string GetUdevProblem() {
-#if defined(__linux__)
+#if defined(__linux__) && !defined(__BIONIC__)
errno = 0;
group* plugdev_group = getgrnam("plugdev");
diff --git a/adb/diagnose_usb.h b/diagnose_usb/include/diagnose_usb.h
similarity index 100%
rename from adb/diagnose_usb.h
rename to diagnose_usb/include/diagnose_usb.h
diff --git a/fastboot/Android.mk b/fastboot/Android.mk
index dfcf090..f5bcc26 100644
--- a/fastboot/Android.mk
+++ b/fastboot/Android.mk
@@ -39,13 +39,15 @@
LOCAL_MODULE_TAGS := debug
LOCAL_MODULE_HOST_OS := darwin linux windows
LOCAL_CFLAGS += -Wall -Wextra -Werror -Wunreachable-code
-LOCAL_REQUIRED_MODULES := mke2fs e2fsdroid mke2fs.conf make_f2fs sload_f2fs
+LOCAL_REQUIRED_MODULES := mke2fs make_f2fs
LOCAL_SRC_FILES_linux := usb_linux.cpp
LOCAL_STATIC_LIBRARIES_linux := libselinux
+LOCAL_REQUIRED_MODULES_linux := e2fsdroid mke2fs.conf sload_f2fs
LOCAL_SRC_FILES_darwin := usb_osx.cpp
LOCAL_STATIC_LIBRARIES_darwin := libselinux
+LOCAL_REQUIRED_MODULES_darwin := e2fsdroid mke2fs.conf sload_f2fs
LOCAL_LDLIBS_darwin := -lpthread -framework CoreFoundation -framework IOKit -framework Carbon
LOCAL_CFLAGS_darwin := -Wno-unused-parameter
diff --git a/healthd/BatteryMonitor.cpp b/healthd/BatteryMonitor.cpp
index 08b8b26..fa79d0b 100644
--- a/healthd/BatteryMonitor.cpp
+++ b/healthd/BatteryMonitor.cpp
@@ -143,7 +143,7 @@
BatteryMonitor::PowerSupplyType BatteryMonitor::readPowerSupplyType(const String8& path) {
std::string buf;
- BatteryMonitor::PowerSupplyType ret;
+ int ret;
struct sysfsStringEnumMap supplyTypeMap[] = {
{ "Unknown", ANDROID_POWER_SUPPLY_TYPE_UNKNOWN },
{ "Battery", ANDROID_POWER_SUPPLY_TYPE_BATTERY },
@@ -164,13 +164,13 @@
if (readFromFile(path, &buf) <= 0)
return ANDROID_POWER_SUPPLY_TYPE_UNKNOWN;
- ret = (BatteryMonitor::PowerSupplyType)mapSysfsString(buf.c_str(), supplyTypeMap);
+ ret = mapSysfsString(buf.c_str(), supplyTypeMap);
if (ret < 0) {
KLOG_WARNING(LOG_TAG, "Unknown power supply type '%s'\n", buf.c_str());
ret = ANDROID_POWER_SUPPLY_TYPE_UNKNOWN;
}
- return ret;
+ return static_cast<BatteryMonitor::PowerSupplyType>(ret);
}
bool BatteryMonitor::getBooleanField(const String8& path) {
diff --git a/init/service.cpp b/init/service.cpp
index f8aca93..694e5e7 100644
--- a/init/service.cpp
+++ b/init/service.cpp
@@ -446,8 +446,8 @@
const std::string& interface_name = args[1];
const std::string& instance_name = args[2];
- const FQName fq_name = FQName(interface_name);
- if (!fq_name.isValid()) {
+ FQName fq_name;
+ if (!FQName::parse(interface_name, &fq_name)) {
return Error() << "Invalid fully-qualified name for interface '" << interface_name << "'";
}
diff --git a/libasyncio/AsyncIO.cpp b/libasyncio/AsyncIO.cpp
index 7430bc8..6149f09 100644
--- a/libasyncio/AsyncIO.cpp
+++ b/libasyncio/AsyncIO.cpp
@@ -17,9 +17,10 @@
#include <asyncio/AsyncIO.h>
#include <sys/syscall.h>
#include <unistd.h>
+#include <cstdint>
+#include <cstring>
int io_setup(unsigned nr, aio_context_t* ctxp) {
- memset(ctxp, 0, sizeof(*ctxp));
return syscall(__NR_io_setup, nr, ctxp);
}
@@ -48,3 +49,11 @@
iocb->aio_nbytes = count;
iocb->aio_offset = offset;
}
+
+void io_prep_pread(struct iocb* iocb, int fd, void* buf, size_t count, long long offset) {
+ io_prep(iocb, fd, buf, count, offset, true);
+}
+
+void io_prep_pwrite(struct iocb* iocb, int fd, void* buf, size_t count, long long offset) {
+ io_prep(iocb, fd, buf, count, offset, false);
+}
diff --git a/libasyncio/include/asyncio/AsyncIO.h b/libasyncio/include/asyncio/AsyncIO.h
index e3fb93a..9620d2a 100644
--- a/libasyncio/include/asyncio/AsyncIO.h
+++ b/libasyncio/include/asyncio/AsyncIO.h
@@ -17,9 +17,9 @@
#ifndef _ASYNCIO_H
#define _ASYNCIO_H
-#include <cstring>
-#include <cstdint>
#include <linux/aio_abi.h>
+#include <stdbool.h>
+#include <stdint.h>
#include <sys/cdefs.h>
#include <sys/types.h>
#include <time.h>
@@ -35,10 +35,14 @@
int io_setup(unsigned nr, aio_context_t* ctxp);
int io_destroy(aio_context_t ctx);
-int io_submit(aio_context_t ctx, long nr, iocb** iocbpp);
-int io_getevents(aio_context_t ctx, long min_nr, long max_nr, io_event* events, timespec* timeout);
-int io_cancel(aio_context_t ctx, iocb*, io_event* result);
-void io_prep(iocb* iocb, int fd, const void* buf, uint64_t count, int64_t offset, bool read);
+int io_submit(aio_context_t ctx, long nr, struct iocb** iocbpp);
+int io_getevents(aio_context_t ctx, long min_nr, long max_nr, struct io_event* events,
+ struct timespec* timeout);
+int io_cancel(aio_context_t ctx, struct iocb*, struct io_event* result);
+
+void io_prep_pread(struct iocb* iocb, int fd, void* buf, size_t count, long long offset);
+void io_prep_pwrite(struct iocb* iocb, int fd, void* buf, size_t count, long long offset);
+void io_prep(struct iocb* iocb, int fd, const void* buf, uint64_t count, int64_t offset, bool read);
#ifdef __cplusplus
};
diff --git a/libion/ion.c b/libion/ion.c
index 5836128..b8de5a4 100644
--- a/libion/ion.c
+++ b/libion/ion.c
@@ -55,7 +55,7 @@
int ion_open() {
int fd = open("/dev/ion", O_RDONLY | O_CLOEXEC);
- if (fd < 0) ALOGE("open /dev/ion failed!\n");
+ if (fd < 0) ALOGE("open /dev/ion failed: %s", strerror(errno));
return fd;
}
@@ -69,7 +69,7 @@
static int ion_ioctl(int fd, int req, void* arg) {
int ret = ioctl(fd, req, arg);
if (ret < 0) {
- ALOGE("ioctl %x failed with code %d: %s\n", req, ret, strerror(errno));
+ ALOGE("ioctl %x failed with code %d: %s", req, ret, strerror(errno));
return -errno;
}
return ret;
@@ -115,12 +115,12 @@
ret = ion_ioctl(fd, ION_IOC_MAP, &data);
if (ret < 0) return ret;
if (data.fd < 0) {
- ALOGE("map ioctl returned negative fd\n");
+ ALOGE("map ioctl returned negative fd");
return -EINVAL;
}
tmp_ptr = mmap(NULL, length, prot, flags, data.fd, offset);
if (tmp_ptr == MAP_FAILED) {
- ALOGE("mmap failed: %s\n", strerror(errno));
+ ALOGE("mmap failed: %s", strerror(errno));
return -errno;
}
*map_fd = data.fd;
@@ -140,7 +140,7 @@
ret = ion_ioctl(fd, ION_IOC_SHARE, &data);
if (ret < 0) return ret;
if (data.fd < 0) {
- ALOGE("share ioctl returned negative fd\n");
+ ALOGE("share ioctl returned negative fd");
return -EINVAL;
}
*share_fd = data.fd;
diff --git a/liblog/logger_write.c b/liblog/logger_write.c
index d03a2b6..2754e6e 100644
--- a/liblog/logger_write.c
+++ b/liblog/logger_write.c
@@ -243,7 +243,7 @@
static int __write_to_log_daemon(log_id_t log_id, struct iovec* vec, size_t nr) {
struct android_log_transport_write* node;
- int ret;
+ int ret, save_errno;
struct timespec ts;
size_t len, i;
@@ -254,20 +254,24 @@
return -EINVAL;
}
+ save_errno = errno;
#if defined(__ANDROID__)
clock_gettime(android_log_clockid(), &ts);
if (log_id == LOG_ID_SECURITY) {
if (vec[0].iov_len < 4) {
+ errno = save_errno;
return -EINVAL;
}
ret = check_log_uid_permissions();
if (ret < 0) {
+ errno = save_errno;
return ret;
}
if (!__android_log_security()) {
/* If only we could reset downstream logd counter */
+ errno = save_errno;
return -EPERM;
}
} else if (log_id == LOG_ID_EVENTS || log_id == LOG_ID_STATS) {
@@ -276,6 +280,7 @@
EventTagMap *m, *f;
if (vec[0].iov_len < 4) {
+ errno = save_errno;
return -EINVAL;
}
@@ -311,6 +316,7 @@
android_closeEventTagMap(f);
}
if (!ret) {
+ errno = save_errno;
return -EPERM;
}
} else {
@@ -340,6 +346,7 @@
}
if (!__android_log_is_loggable_len(prio, tag, len - 1, ANDROID_LOG_VERBOSE)) {
+ errno = save_errno;
return -EPERM;
}
}
@@ -371,21 +378,23 @@
}
}
+ errno = save_errno;
return ret;
}
static int __write_to_log_init(log_id_t log_id, struct iovec* vec, size_t nr) {
+ int ret, save_errno = errno;
+
__android_log_lock();
if (write_to_log == __write_to_log_init) {
- int ret;
-
ret = __write_to_log_initialize();
if (ret < 0) {
__android_log_unlock();
if (!list_empty(&__android_log_persist_write)) {
__write_to_log_daemon(log_id, vec, nr);
}
+ errno = save_errno;
return ret;
}
@@ -394,7 +403,9 @@
__android_log_unlock();
- return write_to_log(log_id, vec, nr);
+ ret = write_to_log(log_id, vec, nr);
+ errno = save_errno;
+ return ret;
}
LIBLOG_ABI_PUBLIC int __android_log_write(int prio, const char* tag,
diff --git a/libsysutils/src/NetlinkEvent.cpp b/libsysutils/src/NetlinkEvent.cpp
index 7f92904..35a3063 100644
--- a/libsysutils/src/NetlinkEvent.cpp
+++ b/libsysutils/src/NetlinkEvent.cpp
@@ -137,6 +137,12 @@
switch(rta->rta_type) {
case IFLA_IFNAME:
asprintf(&mParams[0], "INTERFACE=%s", (char *) RTA_DATA(rta));
+ // We can get the interface change information from sysfs update
+ // already. But in case we missed those message when devices start.
+ // We do a update again when received a kLinkUp event. To make
+ // the message consistent, use IFINDEX here as well since sysfs
+ // uses IFINDEX.
+ asprintf(&mParams[1], "IFINDEX=%d", ifi->ifi_index);
mAction = (ifi->ifi_flags & IFF_LOWER_UP) ? Action::kLinkUp :
Action::kLinkDown;
mSubsystem = strdup("net");
diff --git a/libunwindstack/Unwinder.cpp b/libunwindstack/Unwinder.cpp
index 7da6994..94edb1c 100644
--- a/libunwindstack/Unwinder.cpp
+++ b/libunwindstack/Unwinder.cpp
@@ -77,7 +77,6 @@
return;
}
- // dex_files_->GetMethodInformation(dex_pc - dex_offset, dex_offset, info, &frame->function_name,
dex_files_->GetMethodInformation(maps_, info, dex_pc, &frame->function_name,
&frame->function_offset);
#endif
diff --git a/libutils/Android.bp b/libutils/Android.bp
index 80dcdcb..32caa69 100644
--- a/libutils/Android.bp
+++ b/libutils/Android.bp
@@ -129,7 +129,6 @@
"PropertyMap.cpp",
"RefBase.cpp",
"SharedBuffer.cpp",
- "Static.cpp",
"StopWatch.cpp",
"String8.cpp",
"String16.cpp",
diff --git a/libutils/Static.cpp b/libutils/Static.cpp
deleted file mode 100644
index 3ed07a1..0000000
--- a/libutils/Static.cpp
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * Copyright (C) 2008 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.
- */
-
-// All static variables go here, to control initialization and
-// destruction order in the library.
-
-namespace android {
-
-// For String8.cpp
-extern void initialize_string8();
-extern void terminate_string8();
-
-// For String16.cpp
-extern void initialize_string16();
-extern void terminate_string16();
-
-class LibUtilsFirstStatics
-{
-public:
- LibUtilsFirstStatics()
- {
- initialize_string8();
- initialize_string16();
- }
-
- ~LibUtilsFirstStatics()
- {
- terminate_string16();
- terminate_string8();
- }
-};
-
-static LibUtilsFirstStatics gFirstStatics;
-int gDarwinCantLoadAllObjects = 1;
-
-} // namespace android
diff --git a/libutils/String16.cpp b/libutils/String16.cpp
index ad335c3..84d53dd 100644
--- a/libutils/String16.cpp
+++ b/libutils/String16.cpp
@@ -24,29 +24,16 @@
namespace android {
-static SharedBuffer* gEmptyStringBuf = NULL;
-static char16_t* gEmptyString = NULL;
+static inline char16_t* getEmptyString() {
+ static SharedBuffer* gEmptyStringBuf = [] {
+ SharedBuffer* buf = SharedBuffer::alloc(sizeof(char16_t));
+ char16_t* str = static_cast<char16_t*>(buf->data());
+ *str = 0;
+ return buf;
+ }();
-static inline char16_t* getEmptyString()
-{
gEmptyStringBuf->acquire();
- return gEmptyString;
-}
-
-void initialize_string16()
-{
- SharedBuffer* buf = SharedBuffer::alloc(sizeof(char16_t));
- char16_t* str = (char16_t*)buf->data();
- *str = 0;
- gEmptyStringBuf = buf;
- gEmptyString = str;
-}
-
-void terminate_string16()
-{
- SharedBuffer::bufferFromData(gEmptyString)->release();
- gEmptyStringBuf = NULL;
- gEmptyString = NULL;
+ return static_cast<char16_t*>(gEmptyStringBuf->data());
}
// ---------------------------------------------------------------------------
diff --git a/libutils/String8.cpp b/libutils/String8.cpp
index ad0e72e..580e870 100644
--- a/libutils/String8.cpp
+++ b/libutils/String8.cpp
@@ -40,40 +40,16 @@
// to OS_PATH_SEPARATOR.
#define RES_PATH_SEPARATOR '/'
-static SharedBuffer* gEmptyStringBuf = NULL;
-static char* gEmptyString = NULL;
+static inline char* getEmptyString() {
+ static SharedBuffer* gEmptyStringBuf = [] {
+ SharedBuffer* buf = SharedBuffer::alloc(1);
+ char* str = static_cast<char*>(buf->data());
+ *str = 0;
+ return buf;
+ }();
-extern int gDarwinCantLoadAllObjects;
-int gDarwinIsReallyAnnoying;
-
-void initialize_string8();
-
-static inline char* getEmptyString()
-{
gEmptyStringBuf->acquire();
- return gEmptyString;
-}
-
-void initialize_string8()
-{
- // HACK: This dummy dependency forces linking libutils Static.cpp,
- // which is needed to initialize String8/String16 classes.
- // These variables are named for Darwin, but are needed elsewhere too,
- // including static linking on any platform.
- gDarwinIsReallyAnnoying = gDarwinCantLoadAllObjects;
-
- SharedBuffer* buf = SharedBuffer::alloc(1);
- char* str = (char*)buf->data();
- *str = 0;
- gEmptyStringBuf = buf;
- gEmptyString = str;
-}
-
-void terminate_string8()
-{
- SharedBuffer::bufferFromData(gEmptyString)->release();
- gEmptyStringBuf = NULL;
- gEmptyString = NULL;
+ return static_cast<char*>(gEmptyStringBuf->data());
}
// ---------------------------------------------------------------------------
diff --git a/lmkd/Android.bp b/lmkd/Android.bp
index 3f8a503..76d308a 100644
--- a/lmkd/Android.bp
+++ b/lmkd/Android.bp
@@ -4,10 +4,17 @@
srcs: ["lmkd.c"],
shared_libs: [
"liblog",
- "libprocessgroup",
"libcutils",
],
cflags: ["-Werror"],
init_rc: ["lmkd.rc"],
+
+ product_variables: {
+ debuggable: {
+ cflags: [
+ "-DLMKD_TRACE_KILLS"
+ ],
+ },
+ },
}
diff --git a/lmkd/lmkd.c b/lmkd/lmkd.c
index 15471e0..338e5fa 100644
--- a/lmkd/lmkd.c
+++ b/lmkd/lmkd.c
@@ -29,13 +29,31 @@
#include <sys/mman.h>
#include <sys/socket.h>
#include <sys/types.h>
-#include <time.h>
+#include <sys/sysinfo.h>
#include <unistd.h>
#include <cutils/properties.h>
#include <cutils/sockets.h>
#include <log/log.h>
-#include <processgroup/processgroup.h>
+
+/*
+ * Define LMKD_TRACE_KILLS to record lmkd kills in kernel traces
+ * to profile and correlate with OOM kills
+ */
+#ifdef LMKD_TRACE_KILLS
+
+#define ATRACE_TAG ATRACE_TAG_ALWAYS
+#include <cutils/trace.h>
+
+#define TRACE_KILL_START(pid) ATRACE_INT(__FUNCTION__, pid);
+#define TRACE_KILL_END() ATRACE_INT(__FUNCTION__, 0);
+
+#else /* LMKD_TRACE_KILLS */
+
+#define TRACE_KILL_START(pid)
+#define TRACE_KILL_END()
+
+#endif /* LMKD_TRACE_KILLS */
#ifndef __unused
#define __unused __attribute__((__unused__))
@@ -44,8 +62,6 @@
#define MEMCG_SYSFS_PATH "/dev/memcg/"
#define MEMCG_MEMORY_USAGE "/dev/memcg/memory.usage_in_bytes"
#define MEMCG_MEMORYSW_USAGE "/dev/memcg/memory.memsw.usage_in_bytes"
-#define MEMPRESSURE_WATCH_MEDIUM_LEVEL "medium"
-#define MEMPRESSURE_WATCH_CRITICAL_LEVEL "critical"
#define ZONEINFO_PATH "/proc/zoneinfo"
#define LINE_MAX 128
@@ -72,26 +88,47 @@
static int use_inkernel_interface = 1;
static bool has_inkernel_module;
-/* memory pressure level medium event */
-static int mpevfd[2];
-#define CRITICAL_INDEX 1
-#define MEDIUM_INDEX 0
+/* memory pressure levels */
+enum vmpressure_level {
+ VMPRESS_LEVEL_LOW = 0,
+ VMPRESS_LEVEL_MEDIUM,
+ VMPRESS_LEVEL_CRITICAL,
+ VMPRESS_LEVEL_COUNT
+};
-static int medium_oomadj;
-static int critical_oomadj;
+static const char *level_name[] = {
+ "low",
+ "medium",
+ "critical"
+};
+
+struct mem_size {
+ int free_mem;
+ int free_swap;
+};
+
+struct {
+ int min_free; /* recorded but not used yet */
+ int max_free;
+} low_pressure_mem = { -1, -1 };
+
+static int level_oomadj[VMPRESS_LEVEL_COUNT];
+static int mpevfd[VMPRESS_LEVEL_COUNT] = { -1, -1, -1 };
static bool debug_process_killing;
static bool enable_pressure_upgrade;
static int64_t upgrade_pressure;
static int64_t downgrade_pressure;
static bool is_go_device;
+static bool kill_heaviest_task;
+static unsigned long kill_timeout_ms;
/* control socket listen and data */
static int ctrl_lfd;
static int ctrl_dfd = -1;
static int ctrl_dfd_reopened; /* did we reopen ctrl conn on this loop? */
-/* 2 memory pressure levels, 1 ctrl listen socket, 1 ctrl data socket */
-#define MAX_EPOLL_EVENTS 4
+/* 3 memory pressure levels, 1 ctrl listen socket, 1 ctrl data socket */
+#define MAX_EPOLL_EVENTS 5
static int epollfd;
static int maxevents;
@@ -226,7 +263,7 @@
return 0;
}
-static void writefilestring(char *path, char *s) {
+static void writefilestring(const char *path, char *s) {
int fd = open(path, O_WRONLY | O_CLOEXEC);
int len = strlen(s);
int ret;
@@ -534,6 +571,18 @@
return 0;
}
+static int get_free_memory(struct mem_size *ms) {
+ struct sysinfo si;
+
+ if (sysinfo(&si) < 0)
+ return -1;
+
+ ms->free_mem = (int)(si.freeram * si.mem_unit / PAGE_SIZE);
+ ms->free_swap = (int)(si.freeswap * si.mem_unit / PAGE_SIZE);
+
+ return 0;
+}
+
static int proc_get_size(int pid) {
char path[PATH_MAX];
char line[LINE_MAX];
@@ -586,8 +635,32 @@
return (struct proc *)adjslot_tail(&procadjslot_list[ADJTOSLOT(oomadj)]);
}
+static struct proc *proc_get_heaviest(int oomadj) {
+ struct adjslot_list *head = &procadjslot_list[ADJTOSLOT(oomadj)];
+ struct adjslot_list *curr = head->next;
+ struct proc *maxprocp = NULL;
+ int maxsize = 0;
+ while (curr != head) {
+ int pid = ((struct proc *)curr)->pid;
+ int tasksize = proc_get_size(pid);
+ if (tasksize <= 0) {
+ struct adjslot_list *next = curr->next;
+ pid_remove(pid);
+ curr = next;
+ } else {
+ if (tasksize > maxsize) {
+ maxsize = tasksize;
+ maxprocp = (struct proc *)curr;
+ }
+ curr = curr->next;
+ }
+ }
+ return maxprocp;
+}
+
/* Kill one process specified by procp. Returns the size of the process killed */
-static int kill_one_process(struct proc* procp, int min_score_adj, bool is_critical) {
+static int kill_one_process(struct proc* procp, int min_score_adj,
+ enum vmpressure_level level) {
int pid = procp->pid;
uid_t uid = procp->uid;
char *taskname;
@@ -606,14 +679,18 @@
return -1;
}
+ TRACE_KILL_START(pid);
+
+ r = kill(pid, SIGKILL);
ALOGI(
"Killing '%s' (%d), uid %d, adj %d\n"
" to free %ldkB because system is under %s memory pressure oom_adj %d\n",
- taskname, pid, uid, procp->oomadj, tasksize * page_k, is_critical ? "critical" : "medium",
- min_score_adj);
- r = kill(pid, SIGKILL);
+ taskname, pid, uid, procp->oomadj, tasksize * page_k,
+ level_name[level], min_score_adj);
pid_remove(pid);
+ TRACE_KILL_END();
+
if (r) {
ALOGE("kill(%d): errno=%d", pid, errno);
return -1;
@@ -623,31 +700,40 @@
}
/*
- * Find a process to kill based on the current (possibly estimated) free memory
- * and cached memory sizes. Returns the size of the killed processes.
+ * Find processes to kill to free required number of pages.
+ * If pages_to_free is set to 0 only one process will be killed.
+ * Returns the size of the killed processes.
*/
-static int find_and_kill_process(bool is_critical) {
+static int find_and_kill_processes(enum vmpressure_level level,
+ int pages_to_free) {
int i;
- int killed_size = 0;
- int min_score_adj = is_critical ? critical_oomadj : medium_oomadj;
+ int killed_size;
+ int pages_freed = 0;
+ int min_score_adj = level_oomadj[level];
for (i = OOM_SCORE_ADJ_MAX; i >= min_score_adj; i--) {
struct proc *procp;
-retry:
- procp = proc_adj_lru(i);
+ while (true) {
+ if (is_go_device)
+ procp = proc_adj_lru(i);
+ else
+ procp = proc_get_heaviest(i);
- if (procp) {
- killed_size = kill_one_process(procp, min_score_adj, is_critical);
- if (killed_size < 0) {
- goto retry;
- } else {
- return killed_size;
+ if (!procp)
+ break;
+
+ killed_size = kill_one_process(procp, min_score_adj, level);
+ if (killed_size >= 0) {
+ pages_freed += killed_size;
+ if (pages_freed >= pages_to_free) {
+ return pages_freed;
+ }
}
}
}
- return 0;
+ return pages_freed;
}
static int64_t get_memory_usage(const char* path) {
@@ -674,33 +760,118 @@
return mem_usage;
}
-static void mp_event_common(bool is_critical) {
+void record_low_pressure_levels(struct mem_size *free_mem) {
+ if (low_pressure_mem.min_free == -1 ||
+ low_pressure_mem.min_free > free_mem->free_mem) {
+ if (debug_process_killing) {
+ ALOGI("Low pressure min memory update from %d to %d",
+ low_pressure_mem.min_free, free_mem->free_mem);
+ }
+ low_pressure_mem.min_free = free_mem->free_mem;
+ }
+ /*
+ * Free memory at low vmpressure events occasionally gets spikes,
+ * possibly a stale low vmpressure event with memory already
+ * freed up (no memory pressure should have been reported).
+ * Ignore large jumps in max_free that would mess up our stats.
+ */
+ if (low_pressure_mem.max_free == -1 ||
+ (low_pressure_mem.max_free < free_mem->free_mem &&
+ free_mem->free_mem - low_pressure_mem.max_free < low_pressure_mem.max_free * 0.1)) {
+ if (debug_process_killing) {
+ ALOGI("Low pressure max memory update from %d to %d",
+ low_pressure_mem.max_free, free_mem->free_mem);
+ }
+ low_pressure_mem.max_free = free_mem->free_mem;
+ }
+}
+
+enum vmpressure_level upgrade_level(enum vmpressure_level level) {
+ return (enum vmpressure_level)((level < VMPRESS_LEVEL_CRITICAL) ?
+ level + 1 : level);
+}
+
+enum vmpressure_level downgrade_level(enum vmpressure_level level) {
+ return (enum vmpressure_level)((level > VMPRESS_LEVEL_LOW) ?
+ level - 1 : level);
+}
+
+static inline unsigned long get_time_diff_ms(struct timeval *from,
+ struct timeval *to) {
+ return (to->tv_sec - from->tv_sec) * 1000 +
+ (to->tv_usec - from->tv_usec) / 1000;
+}
+
+static void mp_event_common(enum vmpressure_level level) {
int ret;
unsigned long long evcount;
- int index = is_critical ? CRITICAL_INDEX : MEDIUM_INDEX;
int64_t mem_usage, memsw_usage;
int64_t mem_pressure;
+ enum vmpressure_level lvl;
+ struct mem_size free_mem;
+ static struct timeval last_report_tm;
+ static unsigned long skip_count = 0;
- ret = read(mpevfd[index], &evcount, sizeof(evcount));
- if (ret < 0)
- ALOGE("Error reading memory pressure event fd; errno=%d",
- errno);
+ /*
+ * Check all event counters from low to critical
+ * and upgrade to the highest priority one. By reading
+ * eventfd we also reset the event counters.
+ */
+ for (lvl = VMPRESS_LEVEL_LOW; lvl < VMPRESS_LEVEL_COUNT; lvl++) {
+ if (mpevfd[lvl] != -1 &&
+ read(mpevfd[lvl], &evcount, sizeof(evcount)) > 0 &&
+ evcount > 0 && lvl > level) {
+ level = lvl;
+ }
+ }
+
+ if (kill_timeout_ms) {
+ struct timeval curr_tm;
+ gettimeofday(&curr_tm, NULL);
+ if (get_time_diff_ms(&last_report_tm, &curr_tm) < kill_timeout_ms) {
+ skip_count++;
+ return;
+ }
+ }
+
+ if (skip_count > 0) {
+ if (debug_process_killing) {
+ ALOGI("%lu memory pressure events were skipped after a kill!",
+ skip_count);
+ }
+ skip_count = 0;
+ }
+
+ if (get_free_memory(&free_mem) == 0) {
+ if (level == VMPRESS_LEVEL_LOW) {
+ record_low_pressure_levels(&free_mem);
+ }
+ } else {
+ ALOGE("Failed to get free memory!");
+ return;
+ }
+
+ if (level_oomadj[level] > OOM_SCORE_ADJ_MAX) {
+ /* Do not monitor this pressure level */
+ return;
+ }
mem_usage = get_memory_usage(MEMCG_MEMORY_USAGE);
memsw_usage = get_memory_usage(MEMCG_MEMORYSW_USAGE);
if (memsw_usage < 0 || mem_usage < 0) {
- find_and_kill_process(is_critical);
- return;
+ goto do_kill;
}
// Calculate percent for swappinness.
mem_pressure = (mem_usage * 100) / memsw_usage;
- if (enable_pressure_upgrade && !is_critical) {
+ if (enable_pressure_upgrade && level != VMPRESS_LEVEL_CRITICAL) {
// We are swapping too much.
if (mem_pressure < upgrade_pressure) {
- ALOGI("Event upgraded to critical.");
- is_critical = true;
+ level = upgrade_level(level);
+ if (debug_process_killing) {
+ ALOGI("Event upgraded to %s", level_name[level]);
+ }
}
}
@@ -708,41 +879,74 @@
// kill any process, since enough memory is available.
if (mem_pressure > downgrade_pressure) {
if (debug_process_killing) {
- ALOGI("Ignore %s memory pressure", is_critical ? "critical" : "medium");
+ ALOGI("Ignore %s memory pressure", level_name[level]);
}
return;
- } else if (is_critical && mem_pressure > upgrade_pressure) {
+ } else if (level == VMPRESS_LEVEL_CRITICAL &&
+ mem_pressure > upgrade_pressure) {
if (debug_process_killing) {
ALOGI("Downgrade critical memory pressure");
}
- // Downgrade event to medium, since enough memory available.
- is_critical = false;
+ // Downgrade event, since enough memory available.
+ level = downgrade_level(level);
}
- if (find_and_kill_process(is_critical) == 0) {
- if (debug_process_killing) {
- ALOGI("Nothing to kill");
+do_kill:
+ if (is_go_device) {
+ /* For Go devices kill only one task */
+ if (find_and_kill_processes(level, 0) == 0) {
+ if (debug_process_killing) {
+ ALOGI("Nothing to kill");
+ }
+ }
+ } else {
+ /* If pressure level is less than critical and enough free swap then ignore */
+ if (level < VMPRESS_LEVEL_CRITICAL && free_mem.free_swap > low_pressure_mem.max_free) {
+ if (debug_process_killing) {
+ ALOGI("Ignoring pressure since %d swap pages are available ", free_mem.free_swap);
+ }
+ return;
+ }
+
+ /* Free up enough memory to downgrate the memory pressure to low level */
+ if (free_mem.free_mem < low_pressure_mem.max_free) {
+ int pages_to_free = low_pressure_mem.max_free - free_mem.free_mem;
+ if (debug_process_killing) {
+ ALOGI("Trying to free %d pages", pages_to_free);
+ }
+ int pages_freed = find_and_kill_processes(level, pages_to_free);
+ if (pages_freed < pages_to_free) {
+ if (debug_process_killing) {
+ ALOGI("Unable to free enough memory (pages freed=%d)",
+ pages_freed);
+ }
+ } else {
+ gettimeofday(&last_report_tm, NULL);
+ }
}
}
}
-static void mp_event(uint32_t events __unused) {
- mp_event_common(false);
+static void mp_event_low(uint32_t events __unused) {
+ mp_event_common(VMPRESS_LEVEL_LOW);
+}
+
+static void mp_event_medium(uint32_t events __unused) {
+ mp_event_common(VMPRESS_LEVEL_MEDIUM);
}
static void mp_event_critical(uint32_t events __unused) {
- mp_event_common(true);
+ mp_event_common(VMPRESS_LEVEL_CRITICAL);
}
-static int init_mp_common(char *levelstr, void *event_handler, bool is_critical)
-{
+static bool init_mp_common(void *event_handler, enum vmpressure_level level) {
int mpfd;
int evfd;
int evctlfd;
char buf[256];
struct epoll_event epev;
int ret;
- int mpevfd_index = is_critical ? CRITICAL_INDEX : MEDIUM_INDEX;
+ const char *levelstr = level_name[level];
mpfd = open(MEMCG_SYSFS_PATH "memory.pressure_level", O_RDONLY | O_CLOEXEC);
if (mpfd < 0) {
@@ -783,8 +987,9 @@
goto err;
}
maxevents++;
- mpevfd[mpevfd_index] = evfd;
- return 0;
+ mpevfd[level] = evfd;
+ close(evctlfd);
+ return true;
err:
close(evfd);
@@ -793,17 +998,7 @@
err_open_evctlfd:
close(mpfd);
err_open_mpfd:
- return -1;
-}
-
-static int init_mp_medium()
-{
- return init_mp_common(MEMPRESSURE_WATCH_MEDIUM_LEVEL, (void *)&mp_event, false);
-}
-
-static int init_mp_critical()
-{
- return init_mp_common(MEMPRESSURE_WATCH_CRITICAL_LEVEL, (void *)&mp_event_critical, true);
+ return false;
}
static int init(void) {
@@ -843,15 +1038,18 @@
maxevents++;
has_inkernel_module = !access(INKERNEL_MINFREE_PATH, W_OK);
- use_inkernel_interface = has_inkernel_module && !is_go_device;
+ use_inkernel_interface = has_inkernel_module;
if (use_inkernel_interface) {
ALOGI("Using in-kernel low memory killer interface");
} else {
- ret = init_mp_medium();
- ret |= init_mp_critical();
- if (ret)
+ if (!init_mp_common((void *)&mp_event_low, VMPRESS_LEVEL_LOW) ||
+ !init_mp_common((void *)&mp_event_medium, VMPRESS_LEVEL_MEDIUM) ||
+ !init_mp_common((void *)&mp_event_critical,
+ VMPRESS_LEVEL_CRITICAL)) {
ALOGE("Kernel does not support memory pressure events or in-kernel low memory killer");
+ return -1;
+ }
}
for (i = 0; i <= ADJTOSLOT(OOM_SCORE_ADJ_MAX); i++) {
@@ -892,13 +1090,27 @@
.sched_priority = 1,
};
- medium_oomadj = property_get_int32("ro.lmk.medium", 800);
- critical_oomadj = property_get_int32("ro.lmk.critical", 0);
+ /* By default disable low level vmpressure events */
+ level_oomadj[VMPRESS_LEVEL_LOW] =
+ property_get_int32("ro.lmk.low", OOM_SCORE_ADJ_MAX + 1);
+ level_oomadj[VMPRESS_LEVEL_MEDIUM] =
+ property_get_int32("ro.lmk.medium", 800);
+ level_oomadj[VMPRESS_LEVEL_CRITICAL] =
+ property_get_int32("ro.lmk.critical", 0);
debug_process_killing = property_get_bool("ro.lmk.debug", false);
- enable_pressure_upgrade = property_get_bool("ro.lmk.critical_upgrade", false);
- upgrade_pressure = (int64_t)property_get_int32("ro.lmk.upgrade_pressure", 50);
- downgrade_pressure = (int64_t)property_get_int32("ro.lmk.downgrade_pressure", 60);
+
+ /* By default disable upgrade/downgrade logic */
+ enable_pressure_upgrade =
+ property_get_bool("ro.lmk.critical_upgrade", false);
+ upgrade_pressure =
+ (int64_t)property_get_int32("ro.lmk.upgrade_pressure", 100);
+ downgrade_pressure =
+ (int64_t)property_get_int32("ro.lmk.downgrade_pressure", 100);
+ kill_heaviest_task =
+ property_get_bool("ro.lmk.kill_heaviest_task", true);
is_go_device = property_get_bool("ro.config.low_ram", false);
+ kill_timeout_ms =
+ (unsigned long)property_get_int32("ro.lmk.kill_timeout_ms", 0);
// MCL_ONFAULT pins pages as they fault instead of loading
// everything immediately all at once. (Which would be bad,