Merge changes from topic "healthd_deprecate2" into pi-dev
am: 7498160272
Change-Id: I18b63bfae0890d4e2e7af9ad1a3377334c5139ff
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..46bc02b 100644
--- a/adb/Android.bp
+++ b/adb/Android.bp
@@ -12,6 +12,365 @@
// 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++11 doesn't set _GNU_SOURCE on Windows.
+ "-D_GNU_SOURCE",
+
+ // MinGW hides some things behind _POSIX_SOURCE.
+ "-D_POSIX_SOURCE",
+ ],
+
+ host_ldlibs: [
+ "-lws2_32",
+ "-lgdi32",
+ "-luserenv",
+ ],
+ },
+ },
+}
+
+// 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",
+ ],
+
+ target: {
+ windows: {
+ enabled: true,
+ shared_libs: ["AdbWinApi"],
+ },
+ },
+}
+
+cc_benchmark {
+ name: "adb_benchmark",
+ defaults: ["adb_defaults"],
+
+ srcs: ["transport_benchmark.cpp"],
+ target: {
+ android: {
+ static_libs: [
+ "libadbd",
+ ],
+ },
+ host: {
+ static_libs: [
+ "libadb_host",
+ ],
+ },
+ },
+
+ static_libs: [
+ "libbase",
+ "libcutils",
+ "libcrypto_utils",
+ "libcrypto",
+ "libdiagnose_usb",
+ "liblog",
+ "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"],
+ 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
index c473ed2..8b2d558 100644
--- a/adb/Android.mk
+++ b/adb/Android.mk
@@ -1,388 +1,8 @@
-# Copyright 2005 The Android Open Source Project
-#
-# Android.mk for adb
-#
+LOCAL_PATH := $(call my-dir)
-LOCAL_PATH:= $(call my-dir)
+# Archive adb, adb.exe.
+$(call dist-for-goals,dist_files sdk win_sdk,$(HOST_OUT_EXECUTABLES)/adb)
-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 \
- -D_POSIX_SOURCE
-
-# 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))
+$(call dist-for-goals,dist_files sdk 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.bash b/adb/adb.bash
new file mode 100644
index 0000000..d36bec3
--- /dev/null
+++ b/adb/adb.bash
@@ -0,0 +1,499 @@
+# /* vim: set ai ts=4 ft=sh: */
+#
+# Copyright 2011, 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.
+#
+
+_adb() {
+ if ! type -t "$1" >/dev/null; then
+ return
+ fi
+
+ if type -t _init_completion >/dev/null; then
+ _init_completion || return
+ fi
+
+ local where i cur serial
+ COMPREPLY=()
+
+ serial="${ANDROID_SERIAL:-none}"
+ where=OPTIONS
+ for ((i=1; i <= COMP_CWORD; i++)); do
+ cur="${COMP_WORDS[i]}"
+ case "${cur}" in
+ -s)
+ where=OPT_SERIAL
+ ;;
+ -p)
+ where=OPT_PATH
+ ;;
+ -*)
+ where=OPTIONS
+ ;;
+ *)
+ if [[ $where == OPT_SERIAL ]]; then
+ where=OPT_SERIAL_ARG
+ serial=${cur}
+ else
+ where=COMMAND
+ break
+ fi
+ ;;
+ esac
+ done
+
+ if [[ $where == COMMAND && $i -ge $COMP_CWORD ]]; then
+ where=OPTIONS
+ fi
+
+ OPTIONS="-d -e -s -p"
+ COMMAND="devices connect disconnect push pull sync shell emu logcat lolcat forward jdwp install uninstall bugreport help version start-server kill-server get-state get-serialno status-window remount reboot reboot-bootloader root usb tcpip disable-verity"
+
+ case $where in
+ OPTIONS|OPT_SERIAL|OPT_PATH)
+ COMPREPLY=( $(compgen -W "$OPTIONS $COMMAND" -- "$cur") )
+ ;;
+ OPT_SERIAL_ARG)
+ local devices=$(command adb devices 2> /dev/null | grep -v "List of devices" | awk '{ print $1 }')
+ COMPREPLY=( $(compgen -W "${devices}" -- ${cur}) )
+ ;;
+ COMMAND)
+ if [[ $i -eq $COMP_CWORD ]]; then
+ COMPREPLY=( $(compgen -W "$COMMAND" -- "$cur") )
+ else
+ i=$((i+1))
+ case "${cur}" in
+ install)
+ _adb_cmd_install "$serial" $i
+ ;;
+ sideload)
+ _adb_cmd_sideload "$serial" $i
+ ;;
+ pull)
+ _adb_cmd_pull "$serial" $i
+ ;;
+ push)
+ _adb_cmd_push "$serial" $i
+ ;;
+ reboot)
+ if [[ $COMP_CWORD == $i ]]; then
+ args="bootloader recovery"
+ COMPREPLY=( $(compgen -W "${args}" -- "${COMP_WORDS[i]}") )
+ fi
+ ;;
+ shell)
+ _adb_cmd_shell "$serial" $i
+ ;;
+ uninstall)
+ _adb_cmd_uninstall "$serial" $i
+ ;;
+ esac
+ fi
+ ;;
+ esac
+
+ return 0
+}
+
+_adb_cmd_install() {
+ local serial i cur where
+
+ serial=$1
+ i=$2
+
+ where=OPTIONS
+ for ((; i <= COMP_CWORD; i++)); do
+ cur="${COMP_WORDS[i]}"
+ case "${cur}" in
+ -*)
+ where=OPTIONS
+ ;;
+ *)
+ where=FILE
+ break
+ ;;
+ esac
+ done
+
+ cur="${COMP_WORDS[COMP_CWORD]}"
+ if [[ $where == OPTIONS ]]; then
+ COMPREPLY=( $(compgen -W "-d -l -r -s" -- "${cur}") )
+ return
+ fi
+
+ _adb_util_complete_local_file "${cur}" '!*.apk'
+}
+
+_adb_cmd_sideload() {
+ local serial i cur
+
+ serial=$1
+ i=$2
+
+ cur="${COMP_WORDS[COMP_CWORD]}"
+
+ _adb_util_complete_local_file "${cur}" '!*.zip'
+}
+
+_adb_cmd_push() {
+ local serial IFS=$'\n' i cur
+
+ serial=$1
+ i=$2
+
+ cur="${COMP_WORDS[COMP_CWORD]}"
+
+ if [[ $COMP_CWORD == $i ]]; then
+ _adb_util_complete_local_file "${cur}"
+ elif [[ $COMP_CWORD == $(($i+1)) ]]; then
+ if [ "${cur}" == "" ]; then
+ cur="/"
+ fi
+ _adb_util_list_files $serial "${cur}"
+ fi
+}
+
+_adb_cmd_pull() {
+ local serial IFS=$'\n' i cur
+
+ serial=$1
+ i=$2
+
+ cur="${COMP_WORDS[COMP_CWORD]}"
+
+ if [[ $COMP_CWORD == $i ]]; then
+ if [ "${cur}" == "" ]; then
+ cur="/"
+ fi
+ _adb_util_list_files $serial "${cur}"
+ elif [[ $COMP_CWORD == $(($i+1)) ]]; then
+ _adb_util_complete_local_file "${cur}"
+ fi
+}
+
+_adb_cmd_shell() {
+ local serial IFS=$'\n' i cur
+ local -a args
+
+ serial=$1
+ i=$2
+
+ cur="${COMP_WORDS[i]}"
+ if [ "$serial" != "none" ]; then
+ args=(-s $serial)
+ fi
+
+ if [[ $i -eq $COMP_CWORD && ${cur:0:1} != "/" ]]; then
+ paths=$(command adb ${args[@]} shell echo '$'PATH 2> /dev/null | tr -d '\r' | tr : '\n')
+ COMMAND=$(command adb ${args[@]} shell ls $paths '2>' /dev/null | tr -d '\r' | {
+ while read -r tmp; do
+ command=${tmp##*/}
+ printf '%s\n' "$command"
+ done
+ })
+ COMPREPLY=( $(compgen -W "$COMMAND" -- "$cur") )
+ return 0
+ fi
+
+ i=$((i+1))
+ case "$cur" in
+ ls)
+ _adb_shell_file_command $serial $i "--color -A -C -F -H -L -R -S -Z -a -c -d -f -h -i -k -l -m -n -p -q -r -s -t -u -x -1"
+ ;;
+ cat)
+ _adb_shell_file_command $serial $i "-h -e -t -u -v"
+ ;;
+ dumpsys)
+ _adb_cmd_shell_dumpsys "$serial" $i
+ ;;
+ am)
+ _adb_cmd_shell_am "$serial" $i
+ ;;
+ pm)
+ _adb_cmd_shell_pm "$serial" $i
+ ;;
+ /*)
+ _adb_util_list_files $serial "$cur"
+ ;;
+ *)
+ COMPREPLY=( )
+ ;;
+ esac
+
+ return 0
+}
+
+_adb_cmd_shell_dumpsys() {
+ local serial i cur
+ local -a args
+ local candidates
+
+ unset IFS
+
+ serial=$1
+ i=$2
+
+ if [ "$serial" != "none" ]; then
+ args=(-s $serial)
+ fi
+
+ if (( $i == $COMP_CWORD )) ; then
+ cur="${COMP_WORDS[COMP_CWORD]}"
+ # First line is a header, so need "1d".
+ candidates=$(command adb ${args[@]} shell dumpsys -l 2> /dev/null | sed -e '1d;s/^ *//' | tr -d '\r')
+ candidates="-l $candidates"
+ COMPREPLY=( $(compgen -W "$candidates" -- "$cur") )
+ return 0
+ fi
+
+ COMPREPLY=( )
+ return 0
+}
+
+_adb_cmd_shell_am() {
+ local serial i cur
+ local candidates
+
+ unset IFS
+
+ serial=$1
+ i=$2
+
+ if (( $i == $COMP_CWORD )) ; then
+ cur="${COMP_WORDS[COMP_CWORD]}"
+ candidates="broadcast clear-debug-app clear-watch-heap dumpheap force-stop get-config get-inactive hang idle-maintenance instrument kill kill-all monitor package-importance profile restart screen-compat send-trim-memory set-debug-app set-inactive set-watch-heap stack start startservice start-user stopservice stop-user suppress-resize-config-changes switch-user task to-app-uri to-intent-uri to-uri"
+ COMPREPLY=( $(compgen -W "$candidates" -- "$cur") )
+ return 0
+ fi
+
+ COMPREPLY=( )
+ return 0
+}
+
+
+_adb_cmd_shell_pm() {
+ local serial i cur
+ local candidates
+
+ unset IFS
+
+ serial=$1
+ i=$2
+
+ if (( $i == $COMP_CWORD )) ; then
+ cur="${COMP_WORDS[COMP_CWORD]}"
+ candidates="-l -lf -p clear create-user default-state disable"
+ candidates+=" disable-until-used disable-user dump enable"
+ candidates+=" get-app-link get-install-location get-max-users"
+ candidates+=" get-max-running-users grant hide install"
+ candidates+=" install-abandon install-commit install-create"
+ candidates+=" install-write list move-package"
+ candidates+=" move-primary-storage path remove-user"
+ candidates+=" reset-permissions revoke set-app-link"
+ candidates+=" set-installer set-install-location"
+ candidates+=" set-permission-enforced trim-caches unhide"
+ candidates+=" uninstall"
+ COMPREPLY=( $(compgen -W "$candidates" -- "$cur") )
+ return 0
+ fi
+
+ if (( $i + 1 == $COMP_CWORD )) && [[ "${COMP_WORDS[COMP_CWORD -1]}" == "list" ]] ; then
+ cur="${COMP_WORDS[COMP_CWORD]}"
+ candidates="packages permission-groups permissions instrumentation features libraries users"
+ COMPREPLY=( $(compgen -W "$candidates" -- "$cur") )
+ return 0
+ fi
+
+ COMPREPLY=( )
+ return 0
+}
+
+_adb_cmd_uninstall() {
+ local serial i where cur packages
+
+ serial=$1
+ i=$2
+ if [ "$serial" != "none" ]; then
+ args=(-s $serial)
+ fi
+
+ where=OPTIONS
+ for ((; i <= COMP_CWORD; i++)); do
+ cur="${COMP_WORDS[i]}"
+ case "${cur}" in
+ -*)
+ where=OPTIONS
+ ;;
+ *)
+ where=FILE
+ break
+ ;;
+ esac
+ done
+
+ cur="${COMP_WORDS[COMP_CWORD]}"
+ if [[ $where == OPTIONS ]]; then
+ COMPREPLY=( $(compgen -W "-k" -- "${cur}") )
+ fi
+
+ packages="$(
+ command adb ${args[@]} shell pm list packages '2>' /dev/null 2> /dev/null | tr -d '\r' | {
+ while read -r tmp; do
+ local package=${tmp#package:}
+ echo -n "${package} "
+ done
+ }
+ )"
+
+ COMPREPLY=( ${COMPREPLY[@]:-} $(compgen -W "${packages}" -- "${cur}") )
+}
+
+_adb_shell_file_command() {
+ local serial i cur file options
+ local -a args
+
+ serial=$1
+ i=$2
+ if [ "$serial" != "none" ]; then
+ args=(-s $serial)
+ fi
+ options=$3
+
+ where=OPTIONS
+ for ((; i <= COMP_CWORD; i++)); do
+ cur="${COMP_WORDS[i]}"
+ case "${cur}" in
+ -*)
+ where=OPTIONS
+ ;;
+ *)
+ where=FILE
+ break
+ ;;
+ esac
+ done
+
+ file="${COMP_WORDS[COMP_CWORD]}"
+ if [[ ${file} == "" ]]; then
+ file="/"
+ fi
+
+ case $where in
+ OPTIONS)
+ unset IFS
+ COMPREPLY=( $(compgen -W "$options" -- "$cur") )
+ ;;
+ FILE)
+ _adb_util_list_files $serial "$file"
+ ;;
+ esac
+
+ return 0
+}
+
+_adb_util_list_files() {
+ local serial dir IFS=$'\n'
+ local -a toks
+ local -a args
+
+ serial="$1"
+ file="$2"
+
+ if [ "$serial" != "none" ]; then
+ args=(-s $serial)
+ fi
+
+ if [[ $( command adb ${args[@]} shell ls -dF / '2>/dev/null' | tr -d '\r' ) == "d /" ]] ; then
+ toks=( ${toks[@]-} $(
+ command adb ${args[@]} shell ls -dF ${file}"*" '2>' /dev/null 2> /dev/null | tr -d '\r' | {
+ while read -r tmp; do
+ filetype=${tmp%% *}
+ filename=${tmp:${#filetype}+1}
+ if [[ ${filetype:${#filetype}-1:1} == d ]]; then
+ printf '%s/\n' "$filename"
+ else
+ printf '%s\n' "$filename"
+ fi
+ done
+ }
+ ))
+ else
+ toks=( ${toks[@]-} $(
+ command adb ${args[@]} shell ls -dp ${file}"*" '2>/dev/null' 2> /dev/null | tr -d '\r'
+ ))
+ fi
+
+ # Since we're probably doing file completion here, don't add a space after.
+ if [[ $(type -t compopt) = "builtin" ]]; then
+ compopt -o nospace
+ fi
+
+ COMPREPLY=( ${COMPREPLY[@]:-} "${toks[@]}" )
+}
+
+_adb_util_complete_local_file()
+{
+ local file xspec i j IFS=$'\n'
+ local -a dirs files
+
+ file=$1
+ xspec=$2
+
+ # Since we're probably doing file completion here, don't add a space after.
+ if [[ $(type -t compopt) = "builtin" ]]; then
+ compopt -o plusdirs
+ if [[ "${xspec}" == "" ]]; then
+ COMPREPLY=( ${COMPREPLY[@]:-} $(compgen -f -- "${cur}") )
+ else
+ compopt +o filenames
+ COMPREPLY=( ${COMPREPLY[@]:-} $(compgen -f -X "${xspec}" -- "${cur}") )
+ fi
+ else
+ # Work-around for shells with no compopt
+
+ dirs=( $(compgen -d -- "${cur}" ) )
+
+ if [[ "${xspec}" == "" ]]; then
+ files=( ${COMPREPLY[@]:-} $(compgen -f -- "${cur}") )
+ else
+ files=( ${COMPREPLY[@]:-} $(compgen -f -X "${xspec}" -- "${cur}") )
+ fi
+
+ COMPREPLY=( $(
+ for i in "${files[@]}"; do
+ local skip=
+ for j in "${dirs[@]}"; do
+ if [[ $i == $j ]]; then
+ skip=1
+ break
+ fi
+ done
+ [[ -n $skip ]] || printf "%s\n" "$i"
+ done
+ ))
+
+ COMPREPLY=( ${COMPREPLY[@]:-} $(
+ for i in "${dirs[@]}"; do
+ printf "%s/\n" "$i"
+ done
+ ))
+ fi
+}
+
+
+if [[ $(type -t compopt) = "builtin" ]]; then
+ complete -F _adb adb
+else
+ complete -o nospace -F _adb adb
+fi
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 97%
rename from adb/shell_service.cpp
rename to adb/daemon/shell_service.cpp
index 17c7eba..401c99c 100644
--- a/adb/shell_service.cpp
+++ b/adb/daemon/shell_service.cpp
@@ -334,8 +334,18 @@
// processes, so we need to manually reset back to SIG_DFL here (http://b/35209888).
signal(SIGPIPE, SIG_DFL);
+ // Increase oom_score_adj from -1000, so that the child is visible to the OOM-killer.
+ // Don't treat failure as an error, because old Android kernels explicitly disabled this.
+ int oom_score_adj_fd = adb_open("/proc/self/oom_score_adj", O_WRONLY | O_CLOEXEC);
+ if (oom_score_adj_fd != -1) {
+ const char* oom_score_adj_value = "-950";
+ TEMP_FAILURE_RETRY(
+ adb_write(oom_score_adj_fd, oom_score_adj_value, strlen(oom_score_adj_value)));
+ }
+
if (command_.empty()) {
- execle(_PATH_BSHELL, _PATH_BSHELL, "-", nullptr, cenv.data());
+ // Spawn a login shell if we don't have a command.
+ execle(_PATH_BSHELL, "-" _PATH_BSHELL, nullptr, cenv.data());
} else {
execle(_PATH_BSHELL, _PATH_BSHELL, "-c", command_.c_str(), nullptr, cenv.data());
}
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 7869324..263303f 100644
--- a/adb/daemon/usb.cpp
+++ b/adb/daemon/usb.cpp
@@ -269,7 +269,7 @@
if (h->control < 0) { // might have already done this before
LOG(INFO) << "opening control endpoint " << USB_FFS_ADB_EP0;
- h->control = adb_open(USB_FFS_ADB_EP0, O_RDWR);
+ h->control = adb_open(USB_FFS_ADB_EP0, O_WRONLY);
if (h->control < 0) {
PLOG(ERROR) << "cannot open control endpoint " << USB_FFS_ADB_EP0;
goto err;
@@ -300,18 +300,20 @@
android::base::SetProperty("sys.usb.ffs.ready", "1");
}
- h->bulk_out = adb_open(USB_FFS_ADB_OUT, O_RDWR);
+ h->bulk_out = adb_open(USB_FFS_ADB_OUT, O_RDONLY);
if (h->bulk_out < 0) {
PLOG(ERROR) << "cannot open bulk-out endpoint " << USB_FFS_ADB_OUT;
goto err;
}
- h->bulk_in = adb_open(USB_FFS_ADB_IN, O_RDWR);
+ h->bulk_in = adb_open(USB_FFS_ADB_IN, O_WRONLY);
if (h->bulk_in < 0) {
PLOG(ERROR) << "cannot open bulk-in endpoint " << USB_FFS_ADB_IN;
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/fdevent.cpp b/adb/fdevent.cpp
index 42d851a..cf441cf 100644
--- a/adb/fdevent.cpp
+++ b/adb/fdevent.cpp
@@ -21,6 +21,7 @@
#include "fdevent.h"
#include <fcntl.h>
+#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
@@ -36,6 +37,7 @@
#include <android-base/logging.h>
#include <android-base/stringprintf.h>
#include <android-base/thread_annotations.h>
+#include <android-base/threads.h>
#include "adb_io.h"
#include "adb_trace.h"
@@ -71,21 +73,22 @@
static auto& g_pending_list = *new std::list<fdevent*>();
static std::atomic<bool> terminate_loop(false);
static bool main_thread_valid;
-static unsigned long main_thread_id;
+static uint64_t main_thread_id;
+static bool run_needs_flush = false;
static auto& run_queue_notify_fd = *new unique_fd();
static auto& run_queue_mutex = *new std::mutex();
static auto& run_queue GUARDED_BY(run_queue_mutex) = *new std::deque<std::function<void()>>();
void check_main_thread() {
if (main_thread_valid) {
- CHECK_EQ(main_thread_id, adb_thread_id());
+ CHECK_EQ(main_thread_id, android::base::GetThreadId());
}
}
void set_main_thread() {
main_thread_valid = true;
- main_thread_id = adb_thread_id();
+ main_thread_id = android::base::GetThreadId();
}
static std::string dump_fde(const fdevent* fde) {
@@ -315,7 +318,8 @@
PLOG(FATAL) << "failed to empty run queue notify fd";
}
- fdevent_run_flush();
+ // Mark that we need to flush, and then run it at the end of fdevent_loop.
+ run_needs_flush = true;
}
static void fdevent_run_setup() {
@@ -376,6 +380,11 @@
g_pending_list.pop_front();
fdevent_call_fdfunc(fde);
}
+
+ if (run_needs_flush) {
+ fdevent_run_flush();
+ run_needs_flush = false;
+ }
}
}
diff --git a/adb/fdevent_test.cpp b/adb/fdevent_test.cpp
index e3d5a35..2f0ff18 100644
--- a/adb/fdevent_test.cpp
+++ b/adb/fdevent_test.cpp
@@ -80,30 +80,7 @@
TEST_F(FdeventTest, fdevent_terminate) {
PrepareThread();
-
- std::thread thread(fdevent_loop);
- TerminateThread(thread);
-}
-
-static void FdEventThreadFunc(ThreadArg* arg) {
- std::vector<int> read_fds;
- std::vector<int> write_fds;
-
- read_fds.push_back(arg->first_read_fd);
- for (size_t i = 0; i < arg->middle_pipe_count; ++i) {
- int fds[2];
- ASSERT_EQ(0, adb_socketpair(fds));
- read_fds.push_back(fds[0]);
- write_fds.push_back(fds[1]);
- }
- write_fds.push_back(arg->last_write_fd);
-
- std::vector<std::unique_ptr<FdHandler>> fd_handlers;
- for (size_t i = 0; i < read_fds.size(); ++i) {
- fd_handlers.push_back(std::make_unique<FdHandler>(read_fds[i], write_fds[i]));
- }
-
- fdevent_loop();
+ TerminateThread();
}
TEST_F(FdeventTest, smoke) {
@@ -122,7 +99,26 @@
int reader = fd_pair2[0];
PrepareThread();
- std::thread thread(FdEventThreadFunc, &thread_arg);
+
+ std::vector<std::unique_ptr<FdHandler>> fd_handlers;
+ fdevent_run_on_main_thread([&thread_arg, &fd_handlers]() {
+ std::vector<int> read_fds;
+ std::vector<int> write_fds;
+
+ read_fds.push_back(thread_arg.first_read_fd);
+ for (size_t i = 0; i < thread_arg.middle_pipe_count; ++i) {
+ int fds[2];
+ ASSERT_EQ(0, adb_socketpair(fds));
+ read_fds.push_back(fds[0]);
+ write_fds.push_back(fds[1]);
+ }
+ write_fds.push_back(thread_arg.last_write_fd);
+
+ for (size_t i = 0; i < read_fds.size(); ++i) {
+ fd_handlers.push_back(std::make_unique<FdHandler>(read_fds[i], write_fds[i]));
+ }
+ });
+ WaitForFdeventLoop();
for (size_t i = 0; i < MESSAGE_LOOP_COUNT; ++i) {
std::string read_buffer = MESSAGE;
@@ -132,7 +128,10 @@
ASSERT_EQ(read_buffer, write_buffer);
}
- TerminateThread(thread);
+ fdevent_run_on_main_thread([&fd_handlers]() { fd_handlers.clear(); });
+ WaitForFdeventLoop();
+
+ TerminateThread();
ASSERT_EQ(0, adb_close(writer));
ASSERT_EQ(0, adb_close(reader));
}
@@ -143,7 +142,7 @@
size_t* happened_event_count;
};
-static void InvalidFdEventCallback(int fd, unsigned events, void* userdata) {
+static void InvalidFdEventCallback(int, unsigned events, void* userdata) {
InvalidFdArg* arg = reinterpret_cast<InvalidFdArg*>(userdata);
ASSERT_EQ(arg->expected_events, events);
fdevent_remove(&arg->fde);
@@ -179,7 +178,6 @@
std::vector<int> vec;
PrepareThread();
- std::thread thread(fdevent_loop);
// Block the main thread for a long time while we queue our callbacks.
fdevent_run_on_main_thread([]() {
@@ -194,7 +192,7 @@
});
}
- TerminateThread(thread);
+ TerminateThread();
ASSERT_EQ(1000000u, vec.size());
for (int i = 0; i < 1000000; ++i) {
@@ -218,11 +216,8 @@
std::vector<int> vec;
PrepareThread();
- std::thread thread(fdevent_loop);
-
fdevent_run_on_main_thread(make_appender(&vec, 0));
-
- TerminateThread(thread);
+ TerminateThread();
ASSERT_EQ(100u, vec.size());
for (int i = 0; i < 100; ++i) {
diff --git a/adb/fdevent_test.h b/adb/fdevent_test.h
index 1a2d41c..5a417e0 100644
--- a/adb/fdevent_test.h
+++ b/adb/fdevent_test.h
@@ -16,10 +16,31 @@
#include <gtest/gtest.h>
+#include <condition_variable>
+#include <mutex>
#include <thread>
#include "socket.h"
#include "sysdeps.h"
+#include "sysdeps/chrono.h"
+
+static void WaitForFdeventLoop() {
+ // Sleep for a bit to make sure that network events have propagated.
+ std::this_thread::sleep_for(100ms);
+
+ // fdevent_run_on_main_thread has a guaranteed ordering, and is guaranteed to happen after
+ // socket events, so as soon as our function is called, we know that we've processed all
+ // previous events.
+ std::mutex mutex;
+ std::condition_variable cv;
+ std::unique_lock<std::mutex> lock(mutex);
+ fdevent_run_on_main_thread([&]() {
+ mutex.lock();
+ mutex.unlock();
+ cv.notify_one();
+ });
+ cv.wait(lock);
+}
class FdeventTest : public ::testing::Test {
protected:
@@ -49,6 +70,9 @@
}
dummy_socket->ready(dummy_socket);
dummy = dummy_fds[0];
+
+ thread_ = std::thread([]() { fdevent_loop(); });
+ WaitForFdeventLoop();
}
size_t GetAdditionalLocalSocketCount() {
@@ -56,10 +80,12 @@
return 2;
}
- void TerminateThread(std::thread& thread) {
+ void TerminateThread() {
fdevent_terminate_loop();
ASSERT_TRUE(WriteFdExactly(dummy, "", 1));
- thread.join();
+ thread_.join();
ASSERT_EQ(0, adb_close(dummy));
}
+
+ std::thread thread_;
};
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/socket_test.cpp b/adb/socket_test.cpp
index 6b40056..6c4a8b2 100644
--- a/adb/socket_test.cpp
+++ b/adb/socket_test.cpp
@@ -42,8 +42,6 @@
class LocalSocketTest : public FdeventTest {};
-constexpr auto SLEEP_FOR_FDEVENT = 100ms;
-
TEST_F(LocalSocketTest, smoke) {
// Join two socketpairs with a chain of intermediate socketpairs.
int first[2];
@@ -84,7 +82,6 @@
connect(prev_tail, end);
PrepareThread();
- std::thread thread(fdevent_loop);
for (size_t i = 0; i < MESSAGE_LOOP_COUNT; ++i) {
std::string read_buffer = MESSAGE;
@@ -98,9 +95,9 @@
ASSERT_EQ(0, adb_close(last[1]));
// Wait until the local sockets are closed.
- std::this_thread::sleep_for(SLEEP_FOR_FDEVENT);
+ WaitForFdeventLoop();
ASSERT_EQ(GetAdditionalLocalSocketCount(), fdevent_installed_count());
- TerminateThread(thread);
+ TerminateThread();
}
struct CloseWithPacketArg {
@@ -109,24 +106,39 @@
int cause_close_fd;
};
-static void CloseWithPacketThreadFunc(CloseWithPacketArg* arg) {
- asocket* s = create_local_socket(arg->socket_fd);
- ASSERT_TRUE(s != nullptr);
- arg->bytes_written = 0;
+static void CreateCloser(CloseWithPacketArg* arg) {
+ fdevent_run_on_main_thread([arg]() {
+ asocket* s = create_local_socket(arg->socket_fd);
+ ASSERT_TRUE(s != nullptr);
+ arg->bytes_written = 0;
- std::string data;
- data.resize(MAX_PAYLOAD);
- arg->bytes_written += data.size();
- int ret = s->enqueue(s, std::move(data));
- ASSERT_EQ(1, ret);
+ // On platforms that implement sockets via underlying sockets (e.g. Wine),
+ // a socket can appear to be full, and then become available for writes
+ // again without read being called on the other end. Loop and sleep after
+ // each write to give the underlying implementation time to flush.
+ bool socket_filled = false;
+ for (int i = 0; i < 128; ++i) {
+ std::string data;
+ data.resize(MAX_PAYLOAD);
+ arg->bytes_written += data.size();
+ int ret = s->enqueue(s, std::move(data));
+ if (ret == 1) {
+ socket_filled = true;
+ break;
+ }
+ ASSERT_NE(-1, ret);
- asocket* cause_close_s = create_local_socket(arg->cause_close_fd);
- ASSERT_TRUE(cause_close_s != nullptr);
- cause_close_s->peer = s;
- s->peer = cause_close_s;
- cause_close_s->ready(cause_close_s);
+ std::this_thread::sleep_for(250ms);
+ }
+ ASSERT_TRUE(socket_filled);
- fdevent_loop();
+ asocket* cause_close_s = create_local_socket(arg->cause_close_fd);
+ ASSERT_TRUE(cause_close_s != nullptr);
+ cause_close_s->peer = s;
+ s->peer = cause_close_s;
+ cause_close_s->ready(cause_close_s);
+ });
+ WaitForFdeventLoop();
}
// This test checks if we can close local socket in the following situation:
@@ -143,16 +155,17 @@
arg.cause_close_fd = cause_close_fd[1];
PrepareThread();
- std::thread thread(CloseWithPacketThreadFunc, &arg);
- // Wait until the fdevent_loop() starts.
- std::this_thread::sleep_for(SLEEP_FOR_FDEVENT);
+ CreateCloser(&arg);
+
ASSERT_EQ(0, adb_close(cause_close_fd[0]));
- std::this_thread::sleep_for(SLEEP_FOR_FDEVENT);
+
+ WaitForFdeventLoop();
EXPECT_EQ(1u + GetAdditionalLocalSocketCount(), fdevent_installed_count());
ASSERT_EQ(0, adb_close(socket_fd[0]));
- std::this_thread::sleep_for(SLEEP_FOR_FDEVENT);
+
+ WaitForFdeventLoop();
ASSERT_EQ(GetAdditionalLocalSocketCount(), fdevent_installed_count());
- TerminateThread(thread);
+ TerminateThread();
}
// This test checks if we can read packets from a closing local socket.
@@ -166,11 +179,12 @@
arg.cause_close_fd = cause_close_fd[1];
PrepareThread();
- std::thread thread(CloseWithPacketThreadFunc, &arg);
- // Wait until the fdevent_loop() starts.
- std::this_thread::sleep_for(SLEEP_FOR_FDEVENT);
+ CreateCloser(&arg);
+
+ WaitForFdeventLoop();
ASSERT_EQ(0, adb_close(cause_close_fd[0]));
- std::this_thread::sleep_for(SLEEP_FOR_FDEVENT);
+
+ WaitForFdeventLoop();
EXPECT_EQ(1u + GetAdditionalLocalSocketCount(), fdevent_installed_count());
// Verify if we can read successfully.
@@ -179,9 +193,9 @@
ASSERT_EQ(true, ReadFdExactly(socket_fd[0], buf.data(), buf.size()));
ASSERT_EQ(0, adb_close(socket_fd[0]));
- std::this_thread::sleep_for(SLEEP_FOR_FDEVENT);
+ WaitForFdeventLoop();
ASSERT_EQ(GetAdditionalLocalSocketCount(), fdevent_installed_count());
- TerminateThread(thread);
+ TerminateThread();
}
// This test checks if we can close local socket in the following situation:
@@ -198,15 +212,15 @@
arg.cause_close_fd = cause_close_fd[1];
PrepareThread();
- std::thread thread(CloseWithPacketThreadFunc, &arg);
- // Wait until the fdevent_loop() starts.
- std::this_thread::sleep_for(SLEEP_FOR_FDEVENT);
+ CreateCloser(&arg);
+
+ WaitForFdeventLoop();
EXPECT_EQ(2u + GetAdditionalLocalSocketCount(), fdevent_installed_count());
ASSERT_EQ(0, adb_close(socket_fd[0]));
- std::this_thread::sleep_for(SLEEP_FOR_FDEVENT);
+ WaitForFdeventLoop();
ASSERT_EQ(GetAdditionalLocalSocketCount(), fdevent_installed_count());
- TerminateThread(thread);
+ TerminateThread();
}
// Ensure that if we fail to write output to an fd, we will still flush data coming from it.
@@ -226,7 +240,6 @@
tail->ready(tail);
PrepareThread();
- std::thread thread(fdevent_loop);
EXPECT_TRUE(WriteFdExactly(head_fd[0], "foo", 3));
@@ -242,10 +255,9 @@
adb_close(head_fd[0]);
adb_close(tail_fd[0]);
- // Wait until the local sockets are closed.
- std::this_thread::sleep_for(SLEEP_FOR_FDEVENT);
+ WaitForFdeventLoop();
ASSERT_EQ(GetAdditionalLocalSocketCount(), fdevent_installed_count());
- TerminateThread(thread);
+ TerminateThread();
}
#if defined(__linux__)
@@ -254,21 +266,10 @@
std::string error;
int fd = network_loopback_client(5038, SOCK_STREAM, &error);
ASSERT_GE(fd, 0) << error;
- std::this_thread::sleep_for(200ms);
+ std::this_thread::sleep_for(1s);
ASSERT_EQ(0, adb_close(fd));
}
-struct CloseRdHupSocketArg {
- int socket_fd;
-};
-
-static void CloseRdHupSocketThreadFunc(CloseRdHupSocketArg* arg) {
- asocket* s = create_local_socket(arg->socket_fd);
- ASSERT_TRUE(s != nullptr);
-
- fdevent_loop();
-}
-
// This test checks if we can close sockets in CLOSE_WAIT state.
TEST_F(LocalSocketTest, close_socket_in_CLOSE_WAIT_state) {
std::string error;
@@ -279,22 +280,23 @@
int accept_fd = adb_socket_accept(listen_fd, nullptr, nullptr);
ASSERT_GE(accept_fd, 0);
- CloseRdHupSocketArg arg;
- arg.socket_fd = accept_fd;
PrepareThread();
- std::thread thread(CloseRdHupSocketThreadFunc, &arg);
- // Wait until the fdevent_loop() starts.
- std::this_thread::sleep_for(SLEEP_FOR_FDEVENT);
+ fdevent_run_on_main_thread([accept_fd]() {
+ asocket* s = create_local_socket(accept_fd);
+ ASSERT_TRUE(s != nullptr);
+ });
+
+ WaitForFdeventLoop();
EXPECT_EQ(1u + GetAdditionalLocalSocketCount(), fdevent_installed_count());
// Wait until the client closes its socket.
client_thread.join();
- std::this_thread::sleep_for(SLEEP_FOR_FDEVENT);
+ WaitForFdeventLoop();
ASSERT_EQ(GetAdditionalLocalSocketCount(), fdevent_installed_count());
- TerminateThread(thread);
+ TerminateThread();
}
#endif // defined(__linux__)
diff --git a/adb/sockets.cpp b/adb/sockets.cpp
index e05a3db..0887e6f 100644
--- a/adb/sockets.cpp
+++ b/adb/sockets.cpp
@@ -126,12 +126,12 @@
} else if (rc == -1 && errno == EAGAIN) {
fdevent_add(&s->fde, FDE_WRITE);
return SocketFlushResult::TryAgain;
+ } else {
+ // We failed to write, but it's possible that we can still read from the socket.
+ // Give that a try before giving up.
+ s->has_write_error = true;
+ break;
}
-
- // We failed to write, but it's possible that we can still read from the socket.
- // Give that a try before giving up.
- s->has_write_error = true;
- break;
}
// If we sent the last packet of a closing socket, we can now destroy it.
diff --git a/adb/sysdeps.h b/adb/sysdeps.h
index edeacc1..3be99f6 100644
--- a/adb/sysdeps.h
+++ b/adb/sysdeps.h
@@ -92,11 +92,6 @@
return 0;
}
-static __inline__ unsigned long adb_thread_id()
-{
- return GetCurrentThreadId();
-}
-
static __inline__ void close_on_exec(int fd)
{
/* nothing really */
@@ -621,11 +616,6 @@
return path[0] == '/';
}
-static __inline__ unsigned long adb_thread_id()
-{
- return (unsigned long)gettid();
-}
-
#endif /* !_WIN32 */
static inline void disable_tcp_nagle(int fd) {
diff --git a/adb/sysdeps_test.cpp b/adb/sysdeps_test.cpp
index fd19882..79cebe6 100644
--- a/adb/sysdeps_test.cpp
+++ b/adb/sysdeps_test.cpp
@@ -121,10 +121,13 @@
adb_pollfd pfd[3] = {};
pfd[0].fd = fds[0];
pfd[0].events = POLLRDNORM;
+ pfd[0].revents = ~0;
pfd[1].fd = INT_MAX;
pfd[1].events = POLLRDNORM;
+ pfd[1].revents = ~0;
pfd[2].fd = fds[1];
pfd[2].events = POLLWRNORM;
+ pfd[2].revents = ~0;
ASSERT_TRUE(WriteFdExactly(fds[1], "foo", 4));
@@ -136,6 +139,17 @@
EXPECT_EQ(POLLRDNORM, pfd[0].revents);
EXPECT_EQ(POLLNVAL, pfd[1].revents);
EXPECT_EQ(POLLWRNORM, pfd[2].revents);
+
+ // Make sure that we return immediately if an invalid FD is given.
+ pfd[0].fd = fds[0];
+ pfd[0].events = POLLRDNORM;
+ pfd[0].revents = ~0;
+ pfd[1].fd = INT_MAX;
+ pfd[1].events = POLLRDNORM;
+ pfd[1].revents = ~0;
+ EXPECT_EQ(2, adb_poll(pfd, 2, -1));
+ EXPECT_EQ(POLLRDNORM, pfd[0].revents);
+ EXPECT_EQ(POLLNVAL, pfd[1].revents);
}
TEST_F(sysdeps_poll, duplicate_fd) {
diff --git a/adb/sysdeps_win32.cpp b/adb/sysdeps_win32.cpp
index 62f4ac8..7d35fb6 100644
--- a/adb/sysdeps_win32.cpp
+++ b/adb/sysdeps_win32.cpp
@@ -529,6 +529,7 @@
int skipped = 0;
std::vector<WSAPOLLFD> sockets;
std::vector<adb_pollfd*> original;
+
for (size_t i = 0; i < nfds; ++i) {
FH fh = _fh_from_int(fds[i].fd, __func__);
if (!fh || !fh->used || fh->clazz != &_fh_socket_class) {
@@ -549,6 +550,11 @@
return skipped;
}
+ // If we have any invalid FDs in our FD set, make sure to return immediately.
+ if (skipped > 0) {
+ timeout = 0;
+ }
+
int result = WSAPoll(sockets.data(), sockets.size(), timeout);
if (result == SOCKET_ERROR) {
_socket_set_errno(WSAGetLastError());
@@ -560,7 +566,7 @@
original[i]->revents = sockets[i].revents;
}
- // WSAPoll appears to return the number of unique FDs with avaiable events, instead of how many
+ // WSAPoll appears to return the number of unique FDs with available events, instead of how many
// of the pollfd elements have a non-zero revents field, which is what it and poll are specified
// to do. Ignore its result and calculate the proper return value.
result = 0;
diff --git a/adb/test_adb.py b/adb/test_adb.py
index e771106..3bb433d 100644
--- a/adb/test_adb.py
+++ b/adb/test_adb.py
@@ -162,15 +162,14 @@
Bug: https://code.google.com/p/android/issues/detail?id=21021
"""
- port = 12345
-
with contextlib.closing(
socket.socket(socket.AF_INET, socket.SOCK_STREAM)) as listener:
# Use SO_REUSEADDR so subsequent runs of the test can grab the port
# even if it is in TIME_WAIT.
listener.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
- listener.bind(('127.0.0.1', port))
+ listener.bind(('127.0.0.1', 0))
listener.listen(4)
+ port = listener.getsockname()[1]
# Now that listening has started, start adb emu kill, telling it to
# connect to our mock emulator.
@@ -233,6 +232,24 @@
output.strip(), 'connected to localhost:{}'.format(port))
s.close()
+ def test_already_connected(self):
+ s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+ s.bind(('127.0.0.1', 0))
+ s.listen(2)
+
+ port = s.getsockname()[1]
+ output = subprocess.check_output(
+ ['adb', 'connect', 'localhost:{}'.format(port)])
+
+ self.assertEqual(
+ output.strip(), 'connected to localhost:{}'.format(port))
+
+ # b/31250450: this always returns 0 but probably shouldn't.
+ output = subprocess.check_output(
+ ['adb', 'connect', 'localhost:{}'.format(port)])
+
+ self.assertEqual(
+ output.strip(), 'already connected to localhost:{}'.format(port))
def main():
random.seed(0)
diff --git a/adb/test_device.py b/adb/test_device.py
index d422df2..d39eb14 100644
--- a/adb/test_device.py
+++ b/adb/test_device.py
@@ -1187,7 +1187,7 @@
# Verify that the device ended up with the expected UTF-8 path
output = self.device.shell(
['ls', '/data/local/tmp/adb-test-*'])[0].strip()
- self.assertEqual(remote_path.encode('utf-8'), output)
+ self.assertEqual(remote_path, output)
# pull.
self.device.pull(remote_path, tf.name)
diff --git a/adb/transport.cpp b/adb/transport.cpp
index 6b1a00b..2867d38 100644
--- a/adb/transport.cpp
+++ b/adb/transport.cpp
@@ -17,6 +17,8 @@
#define TRACE_TAG TRANSPORT
#include "sysdeps.h"
+#include "sysdeps/memory.h"
+
#include "transport.h"
#include <ctype.h>
@@ -28,6 +30,7 @@
#include <unistd.h>
#include <algorithm>
+#include <deque>
#include <list>
#include <mutex>
#include <thread>
@@ -38,12 +41,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 +69,113 @@
return next++;
}
+BlockingConnectionAdapter::BlockingConnectionAdapter(std::unique_ptr<BlockingConnection> connection)
+ : underlying_(std::move(connection)) {}
+
+BlockingConnectionAdapter::~BlockingConnectionAdapter() {
+ LOG(INFO) << "BlockingConnectionAdapter(" << this->transport_name_ << "): destructing";
+ Stop();
+}
+
+static void AssumeLocked(std::mutex& mutex) ASSERT_CAPABILITY(mutex) {}
+
+void BlockingConnectionAdapter::Start() {
+ std::lock_guard<std::mutex> lock(mutex_);
+ if (started_) {
+ LOG(FATAL) << "BlockingConnectionAdapter(" << this->transport_name_
+ << "): started multiple times";
+ }
+
+ read_thread_ = std::thread([this]() {
+ LOG(INFO) << this->transport_name_ << ": read thread spawning";
+ while (true) {
+ auto packet = std::make_unique<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]() REQUIRES(mutex_) {
+ return this->stopped_ || !this->write_queue_.empty();
+ });
+
+ AssumeLocked(mutex_);
+
+ 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"); });
+ });
+
+ started_ = true;
+}
+
+void BlockingConnectionAdapter::Stop() {
+ {
+ std::lock_guard<std::mutex> lock(mutex_);
+ if (!started_) {
+ LOG(INFO) << "BlockingConnectionAdapter(" << this->transport_name_ << "): not started";
+ return;
+ }
+
+ if (stopped_) {
+ LOG(INFO) << "BlockingConnectionAdapter(" << this->transport_name_
+ << "): already stopped";
+ return;
+ }
+
+ stopped_ = true;
+ }
+
+ LOG(INFO) << "BlockingConnectionAdapter(" << this->transport_name_ << "): stopping";
+
+ this->underlying_->Close();
+ this->cv_.notify_one();
+
+ // Move the threads out into locals with the lock taken, and then unlock to let them exit.
+ std::thread read_thread;
+ std::thread write_thread;
+
+ {
+ std::lock_guard<std::mutex> lock(mutex_);
+ read_thread = std::move(read_thread_);
+ write_thread = std::move(write_thread_);
+ }
+
+ 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::lock_guard<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 +254,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 +263,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 +465,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 +482,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 +504,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 +596,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 +647,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 +722,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 +742,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..d18c362 100644
--- a/adb/transport.h
+++ b/adb/transport.h
@@ -20,14 +20,17 @@
#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 <android-base/thread_annotations.h>
#include <openssl/rsa.h>
#include "adb.h"
@@ -57,15 +60,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 +112,31 @@
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 started_ GUARDED_BY(mutex_) = false;
+ bool stopped_ GUARDED_BY(mutex_) = false;
+
+ std::unique_ptr<BlockingConnection> underlying_;
+ std::thread read_thread_ GUARDED_BY(mutex_);
+ std::thread write_thread_ GUARDED_BY(mutex_);
+
+ std::deque<std::unique_ptr<apacket>> write_queue_ GUARDED_BY(mutex_);
+ 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 +148,7 @@
unique_fd fd_;
};
-struct UsbConnection : public Connection {
+struct UsbConnection : public BlockingConnection {
explicit UsbConnection(usb_handle* handle) : handle_(handle) {}
~UsbConnection();
@@ -110,7 +169,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 +184,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 +206,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_benchmark.cpp b/adb/transport_benchmark.cpp
new file mode 100644
index 0000000..ffe4cbc
--- /dev/null
+++ b/adb/transport_benchmark.cpp
@@ -0,0 +1,179 @@
+/*
+ * Copyright (C) 2018 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 <stdio.h>
+
+#include <android-base/logging.h>
+#include <benchmark/benchmark.h>
+
+#include "adb_trace.h"
+#include "sysdeps.h"
+#include "transport.h"
+
+#define ADB_CONNECTION_BENCHMARK(benchmark_name, ...) \
+ BENCHMARK_TEMPLATE(benchmark_name, FdConnection, ##__VA_ARGS__) \
+ ->Arg(1) \
+ ->Arg(16384) \
+ ->Arg(MAX_PAYLOAD) \
+ ->UseRealTime()
+
+template <typename ConnectionType>
+std::unique_ptr<Connection> MakeConnection(unique_fd fd);
+
+template <>
+std::unique_ptr<Connection> MakeConnection<FdConnection>(unique_fd fd) {
+ auto fd_connection = std::make_unique<FdConnection>(std::move(fd));
+ return std::make_unique<BlockingConnectionAdapter>(std::move(fd_connection));
+}
+
+template <typename ConnectionType>
+void BM_Connection_Unidirectional(benchmark::State& state) {
+ int fds[2];
+ if (adb_socketpair(fds) != 0) {
+ LOG(FATAL) << "failed to create socketpair";
+ }
+
+ auto client = MakeConnection<ConnectionType>(unique_fd(fds[0]));
+ auto server = MakeConnection<ConnectionType>(unique_fd(fds[1]));
+
+ std::atomic<size_t> received_bytes;
+
+ client->SetReadCallback([](Connection*, std::unique_ptr<apacket>) -> bool { return true; });
+ server->SetReadCallback([&received_bytes](Connection*, std::unique_ptr<apacket> packet) -> bool {
+ received_bytes += packet->payload.size();
+ return true;
+ });
+
+ client->SetErrorCallback(
+ [](Connection*, const std::string& error) { LOG(INFO) << "client closed: " << error; });
+ server->SetErrorCallback(
+ [](Connection*, const std::string& error) { LOG(INFO) << "server closed: " << error; });
+
+ client->Start();
+ server->Start();
+
+ for (auto _ : state) {
+ size_t data_size = state.range(0);
+ std::unique_ptr<apacket> packet = std::make_unique<apacket>();
+ memset(&packet->msg, 0, sizeof(packet->msg));
+ packet->msg.command = A_WRTE;
+ packet->msg.data_length = data_size;
+ packet->payload.resize(data_size);
+
+ memset(&packet->payload[0], 0xff, data_size);
+
+ received_bytes = 0;
+ client->Write(std::move(packet));
+ while (received_bytes < data_size) {
+ continue;
+ }
+ }
+ state.SetBytesProcessed(static_cast<int64_t>(state.iterations()) * state.range(0));
+
+ client->Stop();
+ server->Stop();
+}
+
+ADB_CONNECTION_BENCHMARK(BM_Connection_Unidirectional);
+
+enum class ThreadPolicy {
+ MainThread,
+ SameThread,
+};
+
+template <typename ConnectionType, enum ThreadPolicy Policy>
+void BM_Connection_Echo(benchmark::State& state) {
+ int fds[2];
+ if (adb_socketpair(fds) != 0) {
+ LOG(FATAL) << "failed to create socketpair";
+ }
+
+ auto client = MakeConnection<ConnectionType>(unique_fd(fds[0]));
+ auto server = MakeConnection<ConnectionType>(unique_fd(fds[1]));
+
+ std::atomic<size_t> received_bytes;
+
+ fdevent_reset();
+ std::thread fdevent_thread([]() { fdevent_loop(); });
+
+ client->SetReadCallback([&received_bytes](Connection*, std::unique_ptr<apacket> packet) -> bool {
+ received_bytes += packet->payload.size();
+ return true;
+ });
+
+ static const auto handle_packet = [](Connection* connection, std::unique_ptr<apacket> packet) {
+ connection->Write(std::move(packet));
+ };
+
+ server->SetReadCallback([](Connection* connection, std::unique_ptr<apacket> packet) -> bool {
+ if (Policy == ThreadPolicy::MainThread) {
+ auto raw_packet = packet.release();
+ fdevent_run_on_main_thread([connection, raw_packet]() {
+ std::unique_ptr<apacket> packet(raw_packet);
+ handle_packet(connection, std::move(packet));
+ });
+ } else {
+ handle_packet(connection, std::move(packet));
+ }
+ return true;
+ });
+
+ client->SetErrorCallback(
+ [](Connection*, const std::string& error) { LOG(INFO) << "client closed: " << error; });
+ server->SetErrorCallback(
+ [](Connection*, const std::string& error) { LOG(INFO) << "server closed: " << error; });
+
+ client->Start();
+ server->Start();
+
+ for (auto _ : state) {
+ size_t data_size = state.range(0);
+ std::unique_ptr<apacket> packet = std::make_unique<apacket>();
+ memset(&packet->msg, 0, sizeof(packet->msg));
+ packet->msg.command = A_WRTE;
+ packet->msg.data_length = data_size;
+ packet->payload.resize(data_size);
+
+ memset(&packet->payload[0], 0xff, data_size);
+
+ received_bytes = 0;
+ client->Write(std::move(packet));
+ while (received_bytes < data_size) {
+ continue;
+ }
+ }
+ state.SetBytesProcessed(static_cast<int64_t>(state.iterations()) * state.range(0));
+
+ client->Stop();
+ server->Stop();
+
+ // TODO: Make it so that you don't need to poke the fdevent loop to make it terminate?
+ fdevent_terminate_loop();
+ fdevent_run_on_main_thread([]() {});
+
+ fdevent_thread.join();
+}
+
+ADB_CONNECTION_BENCHMARK(BM_Connection_Echo, ThreadPolicy::SameThread);
+ADB_CONNECTION_BENCHMARK(BM_Connection_Echo, ThreadPolicy::MainThread);
+
+int main(int argc, char** argv) {
+ android::base::SetMinimumLogSeverity(android::base::WARNING);
+ adb_trace_init(argv);
+ ::benchmark::Initialize(&argc, argv);
+ if (::benchmark::ReportUnrecognizedArguments(argc, argv)) return 1;
+ ::benchmark::RunSpecifiedBenchmarks();
+}
diff --git a/adb/transport_local.cpp b/adb/transport_local.cpp
index 560a031..c09fcb7 100644
--- a/adb/transport_local.cpp
+++ b/adb/transport_local.cpp
@@ -45,6 +45,7 @@
#include "adb_unique_fd.h"
#include "adb_utils.h"
#include "sysdeps/chrono.h"
+#include "sysdeps/memory.h"
#if ADB_HOST
@@ -445,13 +446,13 @@
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));
+ auto emulator_connection = std::make_unique<EmulatorConnection>(std::move(fd), adb_port);
+ t->connection = std::make_unique<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)));
+ auto fd_connection = std::make_unique<FdConnection>(std::move(fd));
+ t->connection = std::make_unique<BlockingConnectionAdapter>(std::move(fd_connection));
return fail;
}
diff --git a/adb/transport_usb.cpp b/adb/transport_usb.cpp
index d7565f6..e9a75cd 100644
--- a/adb/transport_usb.cpp
+++ b/adb/transport_usb.cpp
@@ -17,6 +17,7 @@
#define TRACE_TAG TRANSPORT
#include "sysdeps.h"
+#include "sysdeps/memory.h"
#include "transport.h"
#include <stdio.h>
@@ -174,8 +175,8 @@
void init_usb_transport(atransport* t, usb_handle* h) {
D("transport: usb");
- t->connection.reset(new UsbConnection(h));
- t->sync_token = 1;
+ auto connection = std::make_unique<UsbConnection>(h);
+ t->connection = std::make_unique<BlockingConnectionAdapter>(std::move(connection));
t->type = kTransportUsb;
}
diff --git a/base/Android.bp b/base/Android.bp
index 5d70d47..7b0ba11 100644
--- a/base/Android.bp
+++ b/base/Android.bp
@@ -50,6 +50,7 @@
"quick_exit.cpp",
"stringprintf.cpp",
"strings.cpp",
+ "threads.cpp",
"test_utils.cpp",
],
diff --git a/base/include/android-base/test_utils.h b/base/include/android-base/test_utils.h
index 2edafe3..b95fa07 100644
--- a/base/include/android-base/test_utils.h
+++ b/base/include/android-base/test_utils.h
@@ -31,6 +31,8 @@
// Release the ownership of fd, caller is reponsible for closing the
// fd or stream properly.
int release();
+ // Don't remove the temporary file in the destructor.
+ void DoNotRemove() { remove_file_ = false; }
int fd;
char path[1024];
@@ -38,6 +40,8 @@
private:
void init(const std::string& tmp_dir);
+ bool remove_file_ = true;
+
DISALLOW_COPY_AND_ASSIGN(TemporaryFile);
};
diff --git a/adb/transport_mdns_unsupported.cpp b/base/include/android-base/threads.h
similarity index 70%
rename from adb/transport_mdns_unsupported.cpp
rename to base/include/android-base/threads.h
index 387d341..85e65ba 100644
--- a/adb/transport_mdns_unsupported.cpp
+++ b/base/include/android-base/threads.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2016 The Android Open Source Project
+ * Copyright (C) 2018 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,5 +14,15 @@
* limitations under the License.
*/
-/* For when mDNS discovery is unsupported */
-void init_mdns_transport_discovery(void) {}
+#ifndef ANDROID_BASE_THREADS_H
+#define ANDROID_BASE_THREADS_H
+
+#include <stdint.h>
+
+namespace android {
+namespace base {
+uint64_t GetThreadId();
+}
+} // namespace android
+
+#endif
diff --git a/base/logging.cpp b/base/logging.cpp
index a31feef..30d7f8d 100644
--- a/base/logging.cpp
+++ b/base/logging.cpp
@@ -21,6 +21,7 @@
#include "android-base/logging.h"
#include <fcntl.h>
+#include <inttypes.h>
#include <libgen.h>
#include <time.h>
@@ -54,41 +55,7 @@
#include <android-base/macros.h>
#include <android-base/strings.h>
-
-// For gettid.
-#if defined(__APPLE__)
-#include "AvailabilityMacros.h" // For MAC_OS_X_VERSION_MAX_ALLOWED
-#include <stdint.h>
-#include <stdlib.h>
-#include <sys/syscall.h>
-#include <sys/time.h>
-#include <unistd.h>
-#elif defined(__linux__) && !defined(__ANDROID__)
-#include <syscall.h>
-#include <unistd.h>
-#elif defined(_WIN32)
-#include <windows.h>
-#endif
-
-#if defined(_WIN32)
-typedef uint32_t thread_id;
-#else
-typedef pid_t thread_id;
-#endif
-
-static thread_id GetThreadId() {
-#if defined(__BIONIC__)
- return gettid();
-#elif defined(__APPLE__)
- uint64_t tid;
- pthread_threadid_np(NULL, &tid);
- return tid;
-#elif defined(__linux__)
- return syscall(__NR_gettid);
-#elif defined(_WIN32)
- return GetCurrentThreadId();
-#endif
-}
+#include <android-base/threads.h>
namespace {
#if defined(__GLIBC__)
@@ -223,8 +190,8 @@
static_assert(arraysize(log_characters) - 1 == FATAL + 1,
"Mismatch in size of log_characters and values in LogSeverity");
char severity_char = log_characters[severity];
- fprintf(stderr, "%s %c %s %5d %5d %s:%u] %s\n", tag ? tag : "nullptr", severity_char, timestamp,
- getpid(), GetThreadId(), file, line, message);
+ fprintf(stderr, "%s %c %s %5d %5" PRIu64 " %s:%u] %s\n", tag ? tag : "nullptr", severity_char,
+ timestamp, getpid(), GetThreadId(), file, line, message);
}
void DefaultAborter(const char* abort_message) {
diff --git a/base/test_utils.cpp b/base/test_utils.cpp
index 9d8dfb2..1619c21 100644
--- a/base/test_utils.cpp
+++ b/base/test_utils.cpp
@@ -92,7 +92,9 @@
if (fd != -1) {
close(fd);
}
- unlink(path);
+ if (remove_file_) {
+ unlink(path);
+ }
}
int TemporaryFile::release() {
diff --git a/base/threads.cpp b/base/threads.cpp
new file mode 100644
index 0000000..a71382b
--- /dev/null
+++ b/base/threads.cpp
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <android-base/threads.h>
+
+#include <stdint.h>
+#include <unistd.h>
+
+#if defined(__APPLE__)
+#include <pthread.h>
+#elif defined(__linux__) && !defined(__ANDROID__)
+#include <syscall.h>
+#elif defined(_WIN32)
+#include <windows.h>
+#endif
+
+namespace android {
+namespace base {
+
+uint64_t GetThreadId() {
+#if defined(__BIONIC__)
+ return gettid();
+#elif defined(__APPLE__)
+ uint64_t tid;
+ pthread_threadid_np(NULL, &tid);
+ return tid;
+#elif defined(__linux__)
+ return syscall(__NR_gettid);
+#elif defined(_WIN32)
+ return GetCurrentThreadId();
+#endif
+}
+
+} // namespace base
+} // namespace android
diff --git a/bootstat/boot_reason_test.sh b/bootstat/boot_reason_test.sh
index 79702a6..b194bbe 100755
--- a/bootstat/boot_reason_test.sh
+++ b/bootstat/boot_reason_test.sh
@@ -239,6 +239,8 @@
return 0
}
+BAD_BOOTLOADER_REASON=
+
[ "USAGE: EXPECT_PROPERTY <prop> <value> [--allow_failure]
Returns true (0) if current return (regex) value is true and the result matches
@@ -249,9 +251,20 @@
value="${2}"
shift 2
val=`adb shell getprop ${property} 2>&1`
- EXPECT_EQ "${value}" "${val}" for Android property ${property} ||
- [ -n "${1}" ] ||
- save_ret=${?}
+ EXPECT_EQ "${value}" "${val}" for Android property ${property}
+ local_ret=${?}
+ if [ 0 != ${local_ret} -a "ro.boot.bootreason" = "${property}" ]; then
+ if [ -z "${BAD_BOOTLOADER_REASON}" ]; then
+ BAD_BOOTLOADER_REASON=${val}
+ elif [ X"${BAD_BOOTLOADER_REASON}" = X"${val}" ]; then
+ local_ret=0
+ fi
+ fi
+ if [ 0 != ${local_ret} ]; then
+ if [ -z "${1}" ] ; then
+ save_ret=${local_ret}
+ fi
+ fi
return ${save_ret}
}
@@ -287,6 +300,7 @@
bootstat: Service started: /system/bin/bootstat --record_boot_reason
bootstat: Service started: /system/bin/bootstat --record_time_since_factory_reset
bootstat: Service started: /system/bin/bootstat -l
+bootstat: Service started: /system/bin/bootstat --set_system_boot_reason --record_boot_complete --record_boot_reason --record_time_since_factory_reset -l
bootstat: Battery level at shutdown 100%
bootstat: Battery level at startup 100%
init : Parsing file /system/etc/init/bootstat.rc...
@@ -407,29 +421,31 @@
tr ' \f\t\r\n' '_____'`
case ${var} in
watchdog | watchdog,?* ) ;;
- kernel_panic | kernel_panic,?*) ;;
- recovery | recovery,?*) ;;
- bootloader | bootloader,?*) ;;
- cold | cold,?*) ;;
- hard | hard,?*) ;;
- warm | warm,?*) ;;
- shutdown | shutdown,?*) ;;
+ kernel_panic | kernel_panic,?* ) ;;
+ recovery | recovery,?* ) ;;
+ bootloader | bootloader,?* ) ;;
+ cold | cold,?* ) ;;
+ hard | hard,?* ) ;;
+ warm | warm,?* ) ;;
+ shutdown | shutdown,?* ) ;;
reboot,reboot | reboot,reboot,* ) var=${var#reboot,} ; var=${var%,} ;;
reboot,cold | reboot,cold,* ) var=${var#reboot,} ; var=${var%,} ;;
reboot,hard | reboot,hard,* ) var=${var#reboot,} ; var=${var%,} ;;
reboot,warm | reboot,warm,* ) var=${var#reboot,} ; var=${var%,} ;;
reboot,recovery | reboot,recovery,* ) var=${var#reboot,} ; var=${var%,} ;;
reboot,bootloader | reboot,bootloader,* ) var=${var#reboot,} ; var=${var%,} ;;
- reboot | reboot,?*) ;;
+ reboot | reboot,?* ) ;;
# Aliases and Heuristics
- *wdog* | *watchdog* ) var="watchdog" ;;
- *powerkey* ) var="cold,powerkey" ;;
- *panic* | *kernel_panic*) var="kernel_panic" ;;
- *thermal*) var="shutdown,thermal" ;;
- *s3_wakeup*) var="warm,s3_wakeup" ;;
- *hw_reset*) var="hard,hw_reset" ;;
- *bootloader*) var="bootloader" ;;
- *) var="reboot" ;;
+ *wdog* | *watchdog* ) var="watchdog" ;;
+ *powerkey* | *power_key* | *PowerKey* ) var="cold,powerkey" ;;
+ *panic* | *kernel_panic* ) var="kernel_panic" ;;
+ *thermal* ) var="shutdown,thermal" ;;
+ *s3_wakeup* ) var="warm,s3_wakeup" ;;
+ *hw_reset* ) var="hard,hw_reset" ;;
+ *usb* ) var="cold,charger" ;;
+ *rtc* ) var="cold,rtc" ;;
+ *bootloader* ) var="bootloader" ;;
+ * ) var="reboot" ;;
esac
echo ${var}
}
@@ -792,6 +808,63 @@
exitPstore
}
+[ "USAGE: test_kernel_panic_subreason
+
+kernel_panic_subreason test:
+- echo SysRq : Trigger a crash : 'test' | adb shell su root tee /dev/kmsg
+- echo c | adb shell su root tee /proc/sysrq-trigger
+- (wait until screen is up, boot has completed)
+- adb shell getprop sys.boot.reason
+- NB: should report kernel_panic,sysrq,test" ]
+test_kernel_panic_subreason() {
+ checkDebugBuild || return
+ duration_test ">90"
+ panic_msg="kernel_panic,sysrq,test"
+ enterPstore
+ if [ ${?} != 0 ]; then
+ echo " or functional bootloader" >&2
+ panic_msg="\(kernel_panic,sysrq,test\|kernel_panic\)"
+ pstore_ok=true
+ fi
+ echo "SysRq : Trigger a crash : 'test'" | adb shell su root tee /dev/kmsg
+ echo c | adb shell su root tee /proc/sysrq-trigger >/dev/null
+ wait_for_screen
+ EXPECT_PROPERTY sys.boot.reason ${panic_msg}
+ EXPECT_PROPERTY persist.sys.boot.reason ${panic_msg}
+ report_bootstat_logs kernel_panic,sysrq,test \
+ "-bootstat: Unknown boot reason: kernel_panic,sysrq,test"
+ exitPstore
+}
+
+[ "USAGE: test_kernel_panic_hung
+
+kernel_panic_hung test:
+- echo Kernel panic - not synching: hung_task: blocked tasks |
+ adb shell su root tee /dev/kmsg
+- adb reboot warm
+- (wait until screen is up, boot has completed)
+- adb shell getprop sys.boot.reason
+- NB: should report kernel_panic,hung" ]
+test_kernel_panic_hung() {
+ checkDebugBuild || return
+ duration_test
+ panic_msg="kernel_panic,hung"
+ enterPstore
+ if [ ${?} != 0 ]; then
+ echo " or functional bootloader" >&2
+ panic_msg="\(kernel_panic,hung\|reboot,hung\)"
+ pstore_ok=true
+ fi
+ echo "Kernel panic - not syncing: hung_task: blocked tasks" |
+ adb shell su root tee /dev/kmsg
+ adb reboot warm
+ wait_for_screen
+ EXPECT_PROPERTY sys.boot.reason ${panic_msg}
+ EXPECT_PROPERTY persist.sys.boot.reason ${panic_msg}
+ report_bootstat_logs kernel_panic,hung
+ exitPstore
+}
+
[ "USAGE: test_warm
warm test
@@ -1051,12 +1124,12 @@
if [ -z "${2}" ]; then
# Hard coded should shell fail to find them above (search/permission issues)
eval set properties ota cold factory_reset hard battery unknown \
- kernel_panic warm thermal_shutdown userrequested_shutdown \
- shell_reboot adb_reboot Its_Just_So_Hard_reboot \
- bootloader_normal bootloader_watchdog bootloader_kernel_panic \
- bootloader_oem_powerkey bootloader_wdog_reset \
- bootloader_wdog_reset bootloader_wdog_reset bootloader_hard \
- bootloader_recovery
+ kernel_panic kernel_panic_subreason kernel_panic_hung warm \
+ thermal_shutdown userrequested_shutdown shell_reboot adb_reboot \
+ Its_Just_So_Hard_reboot bootloader_normal bootloader_watchdog \
+ bootloader_kernel_panic bootloader_oem_powerkey \
+ bootloader_wdog_reset bootloader_wdog_reset bootloader_wdog_reset \
+ bootloader_hard bootloader_recovery
fi
if [ X"nothing" = X"${1}" ]; then
shift 1
diff --git a/bootstat/bootstat.cpp b/bootstat/bootstat.cpp
index d8ee899..bf82cb7 100644
--- a/bootstat/bootstat.cpp
+++ b/bootstat/bootstat.cpp
@@ -29,7 +29,9 @@
#include <ctime>
#include <map>
#include <memory>
+#include <regex>
#include <string>
+#include <utility>
#include <vector>
#include <android-base/chrono_utils.h>
@@ -139,7 +141,7 @@
// values.
const std::map<std::string, int32_t> kBootReasonMap = {
{"empty", kEmptyBootReason},
- {"unknown", kUnknownBootReason},
+ {"__BOOTSTAT_UNKNOWN__", kUnknownBootReason},
{"normal", 2},
{"recovery", 3},
{"reboot", 4},
@@ -192,12 +194,14 @@
{"s3_wakeup", 51},
{"kernel_panic,sysrq", 52},
{"kernel_panic,NULL", 53},
+ {"kernel_panic,null", 53},
{"kernel_panic,BUG", 54},
+ {"kernel_panic,bug", 54},
{"bootloader", 55},
{"cold", 56},
{"hard", 57},
{"warm", 58},
- {"recovery", 59},
+ // {"recovery", 59}, // Duplicate of enum 3 above. Immediate reuse possible.
{"thermal-shutdown", 60},
{"shutdown,thermal", 61},
{"shutdown,battery", 62},
@@ -228,7 +232,7 @@
{"shutdown,thermal,battery", 87},
{"reboot,its_just_so_hard", 88}, // produced by boot_reason_test
{"reboot,Its Just So Hard", 89}, // produced by boot_reason_test
- {"usb", 90},
+ // {"usb", 90}, // Duplicate of enum 80 above. Immediate reuse possible.
{"charge", 91},
{"oem_tz_crash", 92},
{"uvlo", 93},
@@ -286,6 +290,19 @@
{"oem_sdi_err_fatal", 145},
{"pmic_watchdog", 146},
{"software_master", 147},
+ {"cold,charger", 148},
+ {"cold,rtc", 149},
+ {"cold,rtc,2sec", 150},
+ {"reboot,tool", 151},
+ {"reboot,wdt", 152},
+ {"reboot,unknown", 153},
+ {"kernel_panic,audit", 154},
+ {"kernel_panic,atomic", 155},
+ {"kernel_panic,hung", 156},
+ {"kernel_panic,hung,rcu", 157},
+ {"kernel_panic,init", 158},
+ {"kernel_panic,oom", 159},
+ {"kernel_panic,stack", 160},
};
// Converts a string value representing the reason the system booted to an
@@ -462,11 +479,13 @@
}
return std::string::npos;
}
+
+ operator const std::string&() const { return console; }
};
// If bit error match to needle, correct it.
// Return true if any corrections were discovered and applied.
-bool correctForBer(std::string& reason, const std::string& needle) {
+bool correctForBitError(std::string& reason, const std::string& needle) {
bool corrected = false;
if (reason.length() < needle.length()) return corrected;
const pstoreConsole console(reason);
@@ -484,20 +503,215 @@
return corrected;
}
+// If bit error match to needle, correct it.
+// Return true if any corrections were discovered and applied.
+// Try again if we can replace underline with spaces.
+bool correctForBitErrorOrUnderline(std::string& reason, const std::string& needle) {
+ bool corrected = correctForBitError(reason, needle);
+ std::string _needle(needle);
+ std::transform(_needle.begin(), _needle.end(), _needle.begin(),
+ [](char c) { return (c == '_') ? ' ' : c; });
+ if (needle != _needle) {
+ corrected |= correctForBitError(reason, _needle);
+ }
+ return corrected;
+}
+
+// Converts a string value representing the reason the system booted to a
+// string complying with Android system standard reason.
+void transformReason(std::string& reason) {
+ std::transform(reason.begin(), reason.end(), reason.begin(), ::tolower);
+ std::transform(reason.begin(), reason.end(), reason.begin(),
+ [](char c) { return ::isblank(c) ? '_' : c; });
+ std::transform(reason.begin(), reason.end(), reason.begin(),
+ [](char c) { return ::isprint(c) ? c : '?'; });
+}
+
+// Check subreasons for reboot,<subreason> kernel_panic,sysrq,<subreason> or
+// kernel_panic,<subreason>.
+//
+// If quoted flag is set, pull out and correct single quoted ('), newline (\n)
+// or unprintable character terminated subreason, pos is supplied just beyond
+// first quote. if quoted false, pull out and correct newline (\n) or
+// unprintable character terminated subreason.
+//
+// Heuristics to find termination is painted into a corner:
+
+// single bit error for quote ' that we can block. It is acceptable for
+// the others 7, g in reason. 2/9 chance will miss the terminating quote,
+// but there is always the terminating newline that usually immediately
+// follows to fortify our chances.
+bool likely_single_quote(char c) {
+ switch (static_cast<uint8_t>(c)) {
+ case '\'': // '\''
+ case '\'' ^ 0x01: // '&'
+ case '\'' ^ 0x02: // '%'
+ case '\'' ^ 0x04: // '#'
+ case '\'' ^ 0x08: // '/'
+ return true;
+ case '\'' ^ 0x10: // '7'
+ break;
+ case '\'' ^ 0x20: // '\a' (unprintable)
+ return true;
+ case '\'' ^ 0x40: // 'g'
+ break;
+ case '\'' ^ 0x80: // 0xA7 (unprintable)
+ return true;
+ }
+ return false;
+}
+
+// ::isprint(c) and likely_space() will prevent us from being called for
+// fundamentally printable entries, except for '\r' and '\b'.
+//
+// Except for * and J, single bit errors for \n, all others are non-
+// printable so easy catch. It is _acceptable_ for *, J or j to exist in
+// the reason string, so 2/9 chance we will miss the terminating newline.
+//
+// NB: J might not be acceptable, except if at the beginning or preceded
+// with a space, '(' or any of the quotes and their BER aliases.
+// NB: * might not be acceptable, except if at the beginning or preceded
+// with a space, another *, or any of the quotes or their BER aliases.
+//
+// To reduce the chances to closer to 1/9 is too complicated for the gain.
+bool likely_newline(char c) {
+ switch (static_cast<uint8_t>(c)) {
+ case '\n': // '\n' (unprintable)
+ case '\n' ^ 0x01: // '\r' (unprintable)
+ case '\n' ^ 0x02: // '\b' (unprintable)
+ case '\n' ^ 0x04: // 0x0E (unprintable)
+ case '\n' ^ 0x08: // 0x02 (unprintable)
+ case '\n' ^ 0x10: // 0x1A (unprintable)
+ return true;
+ case '\n' ^ 0x20: // '*'
+ case '\n' ^ 0x40: // 'J'
+ break;
+ case '\n' ^ 0x80: // 0x8A (unprintable)
+ return true;
+ }
+ return false;
+}
+
+// ::isprint(c) will prevent us from being called for all the printable
+// matches below. If we let unprintables through because of this, they
+// get converted to underscore (_) by the validation phase.
+bool likely_space(char c) {
+ switch (static_cast<uint8_t>(c)) {
+ case ' ': // ' '
+ case ' ' ^ 0x01: // '!'
+ case ' ' ^ 0x02: // '"'
+ case ' ' ^ 0x04: // '$'
+ case ' ' ^ 0x08: // '('
+ case ' ' ^ 0x10: // '0'
+ case ' ' ^ 0x20: // '\0' (unprintable)
+ case ' ' ^ 0x40: // 'P'
+ case ' ' ^ 0x80: // 0xA0 (unprintable)
+ case '\t': // '\t'
+ case '\t' ^ 0x01: // '\b' (unprintable) (likely_newline counters)
+ case '\t' ^ 0x02: // '\v' (unprintable)
+ case '\t' ^ 0x04: // '\r' (unprintable) (likely_newline counters)
+ case '\t' ^ 0x08: // 0x01 (unprintable)
+ case '\t' ^ 0x10: // 0x19 (unprintable)
+ case '\t' ^ 0x20: // ')'
+ case '\t' ^ 0x40: // '1'
+ case '\t' ^ 0x80: // 0x89 (unprintable)
+ return true;
+ }
+ return false;
+}
+
+std::string getSubreason(const std::string& content, size_t pos, bool quoted) {
+ static constexpr size_t max_reason_length = 256;
+
+ std::string subReason(content.substr(pos, max_reason_length));
+ // Correct against any known strings that Bit Error Match
+ for (const auto& s : knownReasons) {
+ correctForBitErrorOrUnderline(subReason, s);
+ }
+ std::string terminator(quoted ? "'" : "");
+ for (const auto& m : kBootReasonMap) {
+ if (m.first.length() <= strlen("cold")) continue; // too short?
+ if (correctForBitErrorOrUnderline(subReason, m.first + terminator)) continue;
+ if (m.first.length() <= strlen("reboot,cold")) continue; // short?
+ if (android::base::StartsWith(m.first, "reboot,")) {
+ correctForBitErrorOrUnderline(subReason, m.first.substr(strlen("reboot,")) + terminator);
+ } else if (android::base::StartsWith(m.first, "kernel_panic,sysrq,")) {
+ correctForBitErrorOrUnderline(subReason,
+ m.first.substr(strlen("kernel_panic,sysrq,")) + terminator);
+ } else if (android::base::StartsWith(m.first, "kernel_panic,")) {
+ correctForBitErrorOrUnderline(subReason, m.first.substr(strlen("kernel_panic,")) + terminator);
+ }
+ }
+ for (pos = 0; pos < subReason.length(); ++pos) {
+ char c = subReason[pos];
+ if (!(::isprint(c) || likely_space(c)) || likely_newline(c) ||
+ (quoted && likely_single_quote(c))) {
+ subReason.erase(pos);
+ break;
+ }
+ }
+ transformReason(subReason);
+ return subReason;
+}
+
bool addKernelPanicSubReason(const pstoreConsole& console, std::string& ret) {
// Check for kernel panic types to refine information
- if (console.rfind("SysRq : Trigger a crash") != std::string::npos) {
- // Can not happen, except on userdebug, during testing/debugging.
+ if ((console.rfind("SysRq : Trigger a crash") != std::string::npos) ||
+ (console.rfind("PC is at sysrq_handle_crash+") != std::string::npos)) {
ret = "kernel_panic,sysrq";
+ // Invented for Android to allow daemons that specifically trigger sysrq
+ // to communicate more accurate boot subreasons via last console messages.
+ static constexpr char sysrqSubreason[] = "SysRq : Trigger a crash : '";
+ auto pos = console.rfind(sysrqSubreason);
+ if (pos != std::string::npos) {
+ ret += "," + getSubreason(console, pos + strlen(sysrqSubreason), /* quoted */ true);
+ }
return true;
}
if (console.rfind("Unable to handle kernel NULL pointer dereference at virtual address") !=
std::string::npos) {
- ret = "kernel_panic,NULL";
+ ret = "kernel_panic,null";
return true;
}
if (console.rfind("Kernel BUG at ") != std::string::npos) {
- ret = "kernel_panic,BUG";
+ ret = "kernel_panic,bug";
+ return true;
+ }
+
+ std::string panic("Kernel panic - not syncing: ");
+ auto pos = console.rfind(panic);
+ if (pos != std::string::npos) {
+ static const std::vector<std::pair<const std::string, const std::string>> panicReasons = {
+ {"Out of memory", "oom"},
+ {"out of memory", "oom"},
+ {"Oh boy, that early out of memory", "oom"}, // omg
+ {"BUG!", "bug"},
+ {"hung_task: blocked tasks", "hung"},
+ {"audit: ", "audit"},
+ {"scheduling while atomic", "atomic"},
+ {"Attempted to kill init!", "init"},
+ {"Requested init", "init"},
+ {"No working init", "init"},
+ {"Could not decompress init", "init"},
+ {"RCU Stall", "hung,rcu"},
+ {"stack-protector", "stack"},
+ {"kernel stack overflow", "stack"},
+ {"Corrupt kernel stack", "stack"},
+ {"low stack detected", "stack"},
+ {"corrupted stack end", "stack"},
+ };
+
+ ret = "kernel_panic";
+ for (auto& s : panicReasons) {
+ if (console.find(panic + s.first, pos) != std::string::npos) {
+ ret += "," + s.second;
+ return true;
+ }
+ }
+ auto reason = getSubreason(console, pos + panic.length(), /* newline */ false);
+ if (reason.length() > 3) {
+ ret += "," + reason;
+ }
return true;
}
return false;
@@ -507,32 +721,12 @@
return addKernelPanicSubReason(pstoreConsole(content), ret);
}
-// std::transform Helper callback functions:
-// Converts a string value representing the reason the system booted to a
-// string complying with Android system standard reason.
-char tounderline(char c) {
- return ::isblank(c) ? '_' : c;
-}
-
-char toprintable(char c) {
- return ::isprint(c) ? c : '?';
-}
-
-// Cleanup boot_reason regarding acceptable character set
-void transformReason(std::string& reason) {
- std::transform(reason.begin(), reason.end(), reason.begin(), ::tolower);
- std::transform(reason.begin(), reason.end(), reason.begin(), tounderline);
- std::transform(reason.begin(), reason.end(), reason.begin(), toprintable);
-}
-
const char system_reboot_reason_property[] = "sys.boot.reason";
const char last_reboot_reason_property[] = LAST_REBOOT_REASON_PROPERTY;
const char bootloader_reboot_reason_property[] = "ro.boot.bootreason";
// Scrub, Sanitize, Standardize and Enhance the boot reason string supplied.
std::string BootReasonStrToReason(const std::string& boot_reason) {
- static const size_t max_reason_length = 256;
-
std::string ret(GetProperty(system_reboot_reason_property));
std::string reason(boot_reason);
// If sys.boot.reason == ro.boot.bootreason, let's re-evaluate
@@ -567,26 +761,36 @@
// A series of checks to take some officially unsupported reasons
// reported by the bootloader and find some logical and canonical
// sense. In an ideal world, we would require those bootloaders
- // to behave and follow our standards.
+ // to behave and follow our CTS standards.
+ //
+ // first member is the output
+ // second member is an unanchored regex for an alias
+ //
+ // If output has a prefix of <bang> '!', we do not use it as a
+ // match needle (and drop the <bang> prefix when landing in output),
+ // otherwise look for it as well. This helps keep the scale of the
+ // following table smaller.
static const std::vector<std::pair<const std::string, const std::string>> aliasReasons = {
{"watchdog", "wdog"},
- {"cold,powerkey", "powerkey"},
+ {"cold,powerkey", "powerkey|power_key|PowerKey"},
{"kernel_panic", "panic"},
{"shutdown,thermal", "thermal"},
{"warm,s3_wakeup", "s3_wakeup"},
{"hard,hw_reset", "hw_reset"},
+ {"cold,charger", "usb"},
+ {"cold,rtc", "rtc"},
{"reboot,2sec", "2sec_reboot"},
{"bootloader", ""},
};
- // Either the primary or alias is found _somewhere_ in the reason string.
for (auto& s : aliasReasons) {
- if (reason.find(s.first) != std::string::npos) {
+ size_t firstHasNot = s.first[0] == '!';
+ if (!firstHasNot && (reason.find(s.first) != std::string::npos)) {
ret = s.first;
break;
}
- if (s.second.size() && (reason.find(s.second) != std::string::npos)) {
- ret = s.first;
+ if (s.second.size() && std::regex_search(reason, std::regex(s.second))) {
+ ret = s.first.substr(firstHasNot);
break;
}
}
@@ -625,28 +829,7 @@
static const char cmd[] = "reboot: Restarting system with command '";
size_t pos = console.rfind(cmd);
if (pos != std::string::npos) {
- pos += strlen(cmd);
- std::string subReason(content.substr(pos, max_reason_length));
- // Correct against any known strings that Bit Error Match
- for (const auto& s : knownReasons) {
- correctForBer(subReason, s);
- }
- for (const auto& m : kBootReasonMap) {
- if (m.first.length() <= strlen("cold")) continue; // too short?
- if (correctForBer(subReason, m.first + "'")) continue;
- if (m.first.length() <= strlen("reboot,cold")) continue; // short?
- if (!android::base::StartsWith(m.first, "reboot,")) continue;
- correctForBer(subReason, m.first.substr(strlen("reboot,")) + "'");
- }
- for (pos = 0; pos < subReason.length(); ++pos) {
- char c = subReason[pos];
- // #, &, %, / are common single bit error for ' that we can block
- if (!::isprint(c) || (c == '\'') || (c == '#') || (c == '&') || (c == '%') || (c == '/')) {
- subReason.erase(pos);
- break;
- }
- }
- transformReason(subReason);
+ std::string subReason(getSubreason(content, pos + strlen(cmd), /* quoted */ true));
if (subReason != "") { // Will not land "reboot" as that is too blunt.
if (isKernelRebootReason(subReason)) {
ret = "reboot," + subReason; // User space can't talk kernel reasons.
@@ -684,7 +867,7 @@
if (pos != std::string::npos) {
digits = content.substr(pos + strlen(battery), strlen("100 "));
// correct common errors
- correctForBer(digits, "100 ");
+ correctForBitError(digits, "100 ");
if (digits[0] == '!') digits[0] = '1';
if (digits[1] == '!') digits[1] = '1';
}
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/engine.cpp b/fastboot/engine.cpp
index 60b7124..551ddba 100644
--- a/fastboot/engine.cpp
+++ b/fastboot/engine.cpp
@@ -109,32 +109,32 @@
void fb_set_active(const std::string& slot) {
Action& a = queue_action(OP_COMMAND, "set_active:" + slot);
- a.msg = "Setting current slot to '" + slot + "'...";
+ a.msg = "Setting current slot to '" + slot + "'";
}
void fb_queue_erase(const std::string& partition) {
Action& a = queue_action(OP_COMMAND, "erase:" + partition);
- a.msg = "Erasing '" + partition + "'...";
+ a.msg = "Erasing '" + partition + "'";
}
void fb_queue_flash_fd(const std::string& partition, int fd, uint32_t sz) {
Action& a = queue_action(OP_DOWNLOAD_FD, "");
a.fd = fd;
a.size = sz;
- a.msg = android::base::StringPrintf("Sending '%s' (%d KB)...", partition.c_str(), sz / 1024);
+ a.msg = android::base::StringPrintf("Sending '%s' (%u KB)", partition.c_str(), sz / 1024);
Action& b = queue_action(OP_COMMAND, "flash:" + partition);
- b.msg = "Writing '" + partition + "'...";
+ b.msg = "Writing '" + partition + "'";
}
void fb_queue_flash(const std::string& partition, void* data, uint32_t sz) {
Action& a = queue_action(OP_DOWNLOAD, "");
a.data = data;
a.size = sz;
- a.msg = android::base::StringPrintf("Sending '%s' (%d KB)...", partition.c_str(), sz / 1024);
+ a.msg = android::base::StringPrintf("Sending '%s' (%u KB)", partition.c_str(), sz / 1024);
Action& b = queue_action(OP_COMMAND, "flash:" + partition);
- b.msg = "Writing '" + partition + "'...";
+ b.msg = "Writing '" + partition + "'";
}
void fb_queue_flash_sparse(const std::string& partition, struct sparse_file* s, uint32_t sz,
@@ -142,12 +142,12 @@
Action& a = queue_action(OP_DOWNLOAD_SPARSE, "");
a.data = s;
a.size = 0;
- a.msg = android::base::StringPrintf("Sending sparse '%s' %zu/%zu (%d KB)...", partition.c_str(),
+ a.msg = android::base::StringPrintf("Sending sparse '%s' %zu/%zu (%u KB)", partition.c_str(),
current, total, sz / 1024);
Action& b = queue_action(OP_COMMAND, "flash:" + partition);
- b.msg =
- android::base::StringPrintf("Writing '%s' %zu/%zu...", partition.c_str(), current, total);
+ b.msg = android::base::StringPrintf("Writing sparse '%s' %zu/%zu", partition.c_str(), current,
+ total);
}
static int match(const char* str, const char** value, unsigned count) {
@@ -270,7 +270,7 @@
void fb_queue_reboot() {
Action& a = queue_action(OP_COMMAND, "reboot");
a.func = cb_do_nothing;
- a.msg = "Rebooting...";
+ a.msg = "Rebooting";
}
void fb_queue_command(const std::string& cmd, const std::string& msg) {
@@ -289,7 +289,7 @@
Action& a = queue_action(OP_DOWNLOAD_FD, "");
a.fd = fd;
a.size = sz;
- a.msg = android::base::StringPrintf("Sending '%s' (%d KB)", name.c_str(), sz / 1024);
+ a.msg = android::base::StringPrintf("Sending '%s' (%u KB)", name.c_str(), sz / 1024);
}
void fb_queue_upload(const std::string& outfile) {
@@ -312,7 +312,8 @@
for (auto& a : action_list) {
a->start = now();
if (!a->msg.empty()) {
- fprintf(stderr, "%s\n", a->msg.c_str());
+ fprintf(stderr, "%-50s ", a->msg.c_str());
+ verbose("\n");
}
if (a->op == OP_DOWNLOAD) {
status = fb_download_data(transport, a->data, a->size);
@@ -333,6 +334,7 @@
if (status) break;
} else if (a->op == OP_NOTICE) {
// We already showed the notice because it's in `Action::msg`.
+ fprintf(stderr, "\n");
} else if (a->op == OP_DOWNLOAD_SPARSE) {
status = fb_download_data_sparse(transport, reinterpret_cast<sparse_file*>(a->data));
status = a->func(*a, status, status ? fb_get_error().c_str() : "");
diff --git a/fastboot/fastboot.bash b/fastboot/fastboot.bash
new file mode 100644
index 0000000..dca3b4e
--- /dev/null
+++ b/fastboot/fastboot.bash
@@ -0,0 +1,182 @@
+# /* vim: set ai ts=4 ft=sh: */
+#
+# Copyright 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.
+#
+
+_fastboot() {
+ if ! type -t "$1" >/dev/null; then
+ return
+ fi
+
+ if type -t _init_completion >/dev/null; then
+ _init_completion || return
+ fi
+
+ local where i cur serial
+ COMPREPLY=()
+
+ serial="${ANDROID_SERIAL:-none}"
+ where=OPTIONS
+ for ((i=1; i <= COMP_CWORD; i++)); do
+ cur="${COMP_WORDS[i]}"
+ case "${cur}" in
+ -s)
+ where=OPT_SERIAL
+ ;;
+ --slot)
+ where=OPT_SLOT
+ ;;
+ -*)
+ where=OPTIONS
+ ;;
+ *)
+ if [[ $where == OPT_SERIAL ]]; then
+ where=OPT_SERIAL_ARG
+ serial=${cur}
+ elif [[ $where == OPT_SLOT ]]; then
+ where=OPT_SLOT_ARG
+ else
+ where=COMMAND
+ break
+ fi
+ ;;
+ esac
+ done
+
+ if [[ $where == COMMAND && $i -ge $COMP_CWORD ]]; then
+ where=OPTIONS
+ fi
+
+ OPTIONS="-a -c --disable-verification --disable-verity -h --help -s --set-active --skip-secondary --skip-reboot --slot -u --version -w"
+ COMMAND="continue devices erase flash flashall flashing format getvar get_staged help oem reboot stage update"
+
+ case $where in
+ OPTIONS|OPT_SERIAL)
+ COMPREPLY=( $(compgen -W "$OPTIONS $COMMAND" -- "$cur") )
+ ;;
+ OPT_SERIAL_ARG)
+ local devices=$(command fastboot devices 2> /dev/null | awk '{ print $1 }')
+ COMPREPLY=( $(compgen -W "${devices}" -- ${cur}) )
+ ;;
+ OPT_SLOT_ARG)
+ local slots="a all b other"
+ COMPREPLY=( $(compgen -W "${slots}" -- ${cur}) )
+ ;;
+ COMMAND)
+ if [[ $i -eq $COMP_CWORD ]]; then
+ COMPREPLY=( $(compgen -W "$COMMAND" -- "$cur") )
+ else
+ i=$((i+1))
+ case "${cur}" in
+ flash)
+ _fastboot_cmd_flash "$serial" $i
+ ;;
+ reboot)
+ if [[ $COMP_CWORD == $i ]]; then
+ args="bootloader"
+ COMPREPLY=( $(compgen -W "${args}" -- "${COMP_WORDS[i]}") )
+ fi
+ ;;
+ update)
+ _fastboot_cmd_update "$serial" $i
+ ;;
+ esac
+ fi
+ ;;
+ esac
+
+ return 0
+}
+
+_fastboot_cmd_flash() {
+ local serial i cur
+ local partitions
+
+ serial=$1
+ i=$2
+
+ cur="${COMP_WORDS[COMP_CWORD]}"
+ if [[ $i -eq $COMP_CWORD ]]; then
+ partitions="boot bootloader dtbo modem odm oem product radio recovery system vbmeta vendor"
+ COMPREPLY=( $(compgen -W "$partitions" -- $cur) )
+ else
+ _fastboot_util_complete_local_file "${cur}" '!*.img'
+ fi
+}
+
+_fastboot_cmd_update() {
+ local serial i cur
+
+ serial=$1
+ i=$2
+
+ cur="${COMP_WORDS[COMP_CWORD]}"
+
+ _fastboot_util_complete_local_file "${cur}" '!*.zip'
+}
+
+_fastboot_util_complete_local_file() {
+ local file xspec i j IFS=$'\n'
+ local -a dirs files
+
+ file=$1
+ xspec=$2
+
+ # Since we're probably doing file completion here, don't add a space after.
+ if [[ $(type -t compopt) = "builtin" ]]; then
+ compopt -o plusdirs
+ if [[ "${xspec}" == "" ]]; then
+ COMPREPLY=( ${COMPREPLY[@]:-} $(compgen -f -- "${cur}") )
+ else
+ compopt +o filenames
+ COMPREPLY=( ${COMPREPLY[@]:-} $(compgen -f -X "${xspec}" -- "${cur}") )
+ fi
+ else
+ # Work-around for shells with no compopt
+
+ dirs=( $(compgen -d -- "${cur}" ) )
+
+ if [[ "${xspec}" == "" ]]; then
+ files=( ${COMPREPLY[@]:-} $(compgen -f -- "${cur}") )
+ else
+ files=( ${COMPREPLY[@]:-} $(compgen -f -X "${xspec}" -- "${cur}") )
+ fi
+
+ COMPREPLY=( $(
+ for i in "${files[@]}"; do
+ local skip=
+ for j in "${dirs[@]}"; do
+ if [[ $i == $j ]]; then
+ skip=1
+ break
+ fi
+ done
+ [[ -n $skip ]] || printf "%s\n" "$i"
+ done
+ ))
+
+ COMPREPLY=( ${COMPREPLY[@]:-} $(
+ for i in "${dirs[@]}"; do
+ printf "%s/\n" "$i"
+ done
+ ))
+ fi
+}
+
+if [[ $(type -t compopt) = "builtin" ]]; then
+ complete -F _fastboot fastboot
+else
+ complete -o nospace -F _fastboot fastboot
+fi
diff --git a/fastboot/fastboot.cpp b/fastboot/fastboot.cpp
index 0ce3855..220a96a 100644
--- a/fastboot/fastboot.cpp
+++ b/fastboot/fastboot.cpp
@@ -238,7 +238,7 @@
// Opens a new Transport connected to a device. If |serial| is non-null it will be used to identify
// a specific device, otherwise the first USB device found will be used.
//
-// If |serial| is non-null but invalid, this prints an error message to stderr and returns nullptr.
+// If |serial| is non-null but invalid, this exits.
// Otherwise it blocks until the target is available.
//
// The returned Transport is a singleton, so multiple calls to this function will return the same
@@ -270,9 +270,7 @@
if (net_address != nullptr) {
std::string error;
if (!android::base::ParseNetAddress(net_address, &host, &port, nullptr, &error)) {
- fprintf(stderr, "error: Invalid network address '%s': %s\n", net_address,
- error.c_str());
- return nullptr;
+ die("invalid network address '%s': %s\n", net_address, error.c_str());
}
}
}
@@ -328,117 +326,79 @@
// clang-format off
fprintf(stdout,
/* 1234567890123456789012345678901234567890123456789012345678901234567890123456 */
- "usage: fastboot [ <option> ] <command>\n"
+ "usage: fastboot [OPTION...] COMMAND...\n"
"\n"
- "commands:\n"
- " update <filename> Reflash device from update.zip.\n"
- " Sets the flashed slot as active.\n"
- " flashall Flash boot, system, vendor, and --\n"
- " if found -- recovery. If the device\n"
- " supports slots, the slot that has\n"
- " been flashed to is set as active.\n"
- " Secondary images may be flashed to\n"
- " an inactive slot.\n"
- " flash <partition> [ <filename> ] Write a file to a flash partition.\n"
- " flashing lock Locks the device. Prevents flashing.\n"
- " flashing unlock Unlocks the device. Allows flashing\n"
- " any partition except\n"
- " bootloader-related partitions.\n"
- " flashing lock_critical Prevents flashing bootloader-related\n"
- " partitions.\n"
- " flashing unlock_critical Enables flashing bootloader-related\n"
- " partitions.\n"
- " flashing get_unlock_ability Queries bootloader to see if the\n"
- " device is unlocked.\n"
- " flashing get_unlock_bootloader_nonce Queries the bootloader to get the\n"
- " unlock nonce.\n"
- " flashing unlock_bootloader <request> Issue unlock bootloader using request.\n"
- " flashing lock_bootloader Locks the bootloader to prevent\n"
- " bootloader version rollback.\n"
- " erase <partition> Erase a flash partition.\n"
- " format[:[<fs type>][:[<size>]] <partition>\n"
- " Format a flash partition. Can\n"
- " override the fs type and/or size\n"
- " the bootloader reports.\n"
- " getvar <variable> Display a bootloader variable.\n"
- " set_active <slot> Sets the active slot. If slots are\n"
- " not supported, this does nothing.\n"
- " boot <kernel> [ <ramdisk> [ <second> ] ] Download and boot kernel.\n"
- " flash:raw <bootable-partition> <kernel> [ <ramdisk> [ <second> ] ]\n"
- " Create bootimage and flash it.\n"
- " devices [-l] List all connected devices [with\n"
- " device paths].\n"
- " continue Continue with autoboot.\n"
- " reboot [bootloader|emergency] Reboot device [into bootloader or emergency mode].\n"
- " reboot-bootloader Reboot device into bootloader.\n"
- " oem <parameter1> ... <parameterN> Executes oem specific command.\n"
- " stage <infile> Sends contents of <infile> to stage for\n"
- " the next command. Supported only on\n"
- " Android Things devices.\n"
- " get_staged <outfile> Receives data to <outfile> staged by the\n"
- " last command. Supported only on Android\n"
- " Things devices.\n"
- " help Show this help message.\n"
+ "flashing:\n"
+ " update ZIP Flash all partitions from an update.zip package.\n"
+ " flashall Flash all partitions from $ANDROID_PRODUCT_OUT.\n"
+ " On A/B devices, flashed slot is set as active.\n"
+ " Secondary images may be flashed to inactive slot.\n"
+ " flash PARTITION [FILENAME]\n"
+ " Flash given partition only.\n"
+ "\n"
+ "basics:\n"
+ " devices [-l] List devices in bootloader (-l: with device paths).\n"
+ " getvar NAME Display given bootloader variable.\n"
+ " reboot [bootloader] Reboot device.\n"
+ "\n"
+ "locking/unlocking:\n"
+ " flashing lock|unlock Lock/unlock partitions for flashing\n"
+ " flashing lock_critical|unlock_critical\n"
+ " Lock/unlock 'critical' bootloader partitions.\n"
+ " flashing get_unlock_ability\n"
+ " Check whether unlocking is allowed (1) or not(0).\n"
+ "\n"
+ "advanced:\n"
+ " erase PARTITION Erase a flash partition.\n"
+ " format[:FS_TYPE[:SIZE]] PARTITION\n"
+ " Format a flash partition.\n"
+ " set_active SLOT Set the active slot.\n"
+ " oem [COMMAND...] Execute OEM-specific command.\n"
+ "\n"
+ "boot image:\n"
+ " boot KERNEL [RAMDISK [SECOND]]\n"
+ " Download and boot kernel from RAM.\n"
+ " flash:raw PARTITION KERNEL [RAMDISK [SECOND]]\n"
+ " Create boot image and flash it.\n"
+ // TODO: give -c a long option, and remove the short options for this group?
+ " -c CMDLINE Override kernel command line.\n"
+ " --base ADDRESS Set kernel base address (default: 0x10000000).\n"
+ " --kernel-offset Set kernel offset (default: 0x00008000).\n"
+ " --ramdisk-offset Set ramdisk offset (default: 0x01000000).\n"
+ " --tags-offset Set tags offset (default: 0x00000100).\n"
+ " --page-size BYTES Set flash page size (default: 2048).\n"
+ " --header-version VERSION Set boot image header version.\n"
+ "\n"
+ // TODO: what device(s) used this? is there any documentation?
+ //" continue Continue with autoboot.\n"
+ //"\n"
+ "Android Things:\n"
+ " stage IN_FILE Sends given file to stage for the next command.\n"
+ " get_staged OUT_FILE Writes data staged by the last command to a file.\n"
"\n"
"options:\n"
- " -w Erase userdata and cache (and format\n"
- " if supported by partition type).\n"
- " -u Do not erase partition before\n"
- " formatting.\n"
- " -s <specific device> Specify a device. For USB, provide either\n"
- " a serial number or path to device port.\n"
- " For ethernet, provide an address in the\n"
- " form <protocol>:<hostname>[:port] where\n"
- " <protocol> is either tcp or udp.\n"
- " -c <cmdline> Override kernel commandline.\n"
- " -i <vendor id> Specify a custom USB vendor id.\n"
- " -b, --base <base_addr> Specify a custom kernel base\n"
- " address (default: 0x10000000).\n"
- " --kernel-offset Specify a custom kernel offset.\n"
- " (default: 0x00008000)\n"
- " --ramdisk-offset Specify a custom ramdisk offset.\n"
- " (default: 0x01000000)\n"
- " --tags-offset Specify a custom tags offset.\n"
- " (default: 0x00000100)\n"
- " -n, --page-size <page size> Specify the nand page size\n"
- " (default: 2048).\n"
- " -S <size>[K|M|G] Automatically sparse files greater\n"
- " than 'size'. 0 to disable.\n"
- " --slot <slot> Specify slot name to be used if the\n"
- " device supports slots. All operations\n"
- " on partitions that support slots will\n"
- " be done on the slot specified.\n"
- " 'all' can be given to refer to all slots.\n"
- " 'other' can be given to refer to a\n"
- " non-current slot. If this flag is not\n"
- " used, slotted partitions will default\n"
- " to the current active slot.\n"
- " -a, --set-active[=<slot>] Sets the active slot. If no slot is\n"
- " provided, this will default to the value\n"
- " given by --slot. If slots are not\n"
- " supported, this does nothing. This will\n"
- " run after all non-reboot commands.\n"
- " --skip-secondary Will not flash secondary slots when\n"
- " performing a flashall or update. This\n"
- " will preserve data on other slots.\n"
- " --skip-reboot Will not reboot the device when\n"
- " performing commands that normally\n"
- " trigger a reboot.\n"
- " --disable-verity Set the disable-verity flag in the\n"
- " the vbmeta image being flashed.\n"
- " --disable-verification Set the disable-verification flag in"
- " the vbmeta image being flashed.\n"
+ " -w Wipe userdata.\n"
+ " -u Do not erase partition first when formatting.\n"
+ " -s SERIAL Specify a USB device.\n"
+ " -s tcp|udp:HOST[:PORT] Specify a network device.\n"
+ // TODO: remove -i?
+ " -i VENDOR_ID Filter devices by USB vendor id.\n"
+ " -S SIZE[K|M|G] Use sparse files above this limit (0 to disable).\n"
+ " --slot SLOT Use SLOT; 'all' for both slots, 'other' for\n"
+ " non-current slot (default: current active slot).\n"
+ " --set-active[=SLOT] Sets the active slot before rebooting.\n"
+ " --skip-secondary Don't flash secondary slots in flashall/update.\n"
+ " --skip-reboot Don't reboot device after flashing.\n"
+ " --disable-verity Sets disable-verity when flashing vbmeta.\n"
+ " --disable-verification Sets disable-verification when flashing vbmeta.\n"
#if !defined(_WIN32)
- " --wipe-and-use-fbe On devices which support it,\n"
- " erase userdata and cache, and\n"
- " enable file-based encryption\n"
+ " --wipe-and-use-fbe Enable file-based encryption, wiping userdata.\n"
#endif
- " --unbuffered Do not buffer input or output.\n"
- " --version Display version.\n"
- " --header-version Set boot image header version while\n"
- " using flash:raw and boot commands to \n"
- " to create a boot image.\n"
- " -h, --help show this message.\n"
+ // TODO: remove --unbuffered?
+ " --unbuffered Don't buffer input or output.\n"
+ " --verbose, -v Verbose output.\n"
+ " --version Display version.\n"
+ " --help, -h Show this message.\n"
);
// clang-format off
return 0;
@@ -548,7 +508,7 @@
die("make_temporary_directory not supported under Windows, sorry!");
}
-static int make_temporary_fd() {
+static int make_temporary_fd(const char* /*what*/) {
// TODO: reimplement to avoid leaking a FILE*.
return fileno(tmpfile());
}
@@ -564,18 +524,16 @@
static std::string make_temporary_directory() {
std::string result(make_temporary_template());
if (mkdtemp(&result[0]) == nullptr) {
- fprintf(stderr, "Unable to create temporary directory: %s\n", strerror(errno));
- return "";
+ die("unable to create temporary directory: %s", strerror(errno));
}
return result;
}
-static int make_temporary_fd() {
+static int make_temporary_fd(const char* what) {
std::string path_template(make_temporary_template());
int fd = mkstemp(&path_template[0]);
if (fd == -1) {
- fprintf(stderr, "Unable to create temporary file: %s\n", strerror(errno));
- return -1;
+ die("failed to create temporary file for %s: %s\n", what, strerror(errno));
}
unlink(path_template.c_str());
return fd;
@@ -585,16 +543,11 @@
static std::string create_fbemarker_tmpdir() {
std::string dir = make_temporary_directory();
- if (dir.empty()) {
- fprintf(stderr, "Unable to create local temp directory for FBE marker\n");
- return "";
- }
std::string marker_file = dir + "/" + convert_fbe_marker_filename;
int fd = open(marker_file.c_str(), O_CREAT | O_WRONLY | O_CLOEXEC, 0666);
if (fd == -1) {
- fprintf(stderr, "Unable to create FBE marker file %s locally: %d, %s\n",
- marker_file.c_str(), errno, strerror(errno));
- return "";
+ die("unable to create FBE marker file %s locally: %s",
+ marker_file.c_str(), strerror(errno));
}
close(fd);
return dir;
@@ -615,10 +568,7 @@
}
static int unzip_to_file(ZipArchiveHandle zip, const char* entry_name) {
- unique_fd fd(make_temporary_fd());
- if (fd == -1) {
- die("failed to create temporary file for '%s': %s", entry_name, strerror(errno));
- }
+ unique_fd fd(make_temporary_fd(entry_name));
ZipString zip_entry_name(entry_name);
ZipEntry zip_entry;
@@ -779,8 +729,8 @@
static int64_t get_target_sparse_limit(Transport* transport) {
std::string max_download_size;
if (!fb_getvar(transport, "max-download-size", &max_download_size) ||
- max_download_size.empty()) {
- fprintf(stderr, "target didn't report max-download-size\n");
+ max_download_size.empty()) {
+ verbose("target didn't report max-download-size");
return 0;
}
@@ -792,9 +742,7 @@
fprintf(stderr, "couldn't parse max-download-size '%s'\n", max_download_size.c_str());
return 0;
}
- if (limit > 0) {
- fprintf(stderr, "target reported max download size of %" PRId64 " bytes\n", limit);
- }
+ if (limit > 0) verbose("target reported max download size of %" PRId64 " bytes", limit);
return limit;
}
@@ -885,10 +833,7 @@
return;
}
- int fd = make_temporary_fd();
- if (fd == -1) {
- die("Failed to create temporary file for vbmeta rewriting");
- }
+ int fd = make_temporary_fd("vbmeta rewriting");
std::string data;
if (!android::base::ReadFdToString(buf->fd, &data)) {
@@ -1312,18 +1257,6 @@
return result;
}
-static void do_bypass_unlock_command(std::vector<std::string>* args) {
- if (args->empty()) syntax_error("missing unlock_bootloader request");
-
- std::string filename = next_arg(args);
-
- int64_t sz;
- void* data = load_file(filename.c_str(), &sz);
- if (data == nullptr) die("could not load '%s': %s", filename.c_str(), strerror(errno));
- fb_queue_download("unlock_message", data, sz);
- fb_queue_command("flashing unlock_bootloader", "unlocking bootloader");
-}
-
static void do_oem_command(const std::string& cmd, std::vector<std::string>* args) {
if (args->empty()) syntax_error("empty oem command");
@@ -1502,7 +1435,6 @@
bool wants_wipe = false;
bool wants_reboot = false;
bool wants_reboot_bootloader = false;
- bool wants_reboot_emergency = false;
bool skip_reboot = false;
bool wants_set_active = false;
bool skip_secondary = false;
@@ -1527,12 +1459,13 @@
{"tags-offset", required_argument, 0, 't'},
{"help", no_argument, 0, 'h'},
{"unbuffered", no_argument, 0, 0},
- {"version", no_argument, 0, 0},
{"slot", required_argument, 0, 0},
{"set_active", optional_argument, 0, 'a'},
{"set-active", optional_argument, 0, 'a'},
{"skip-secondary", no_argument, 0, 0},
{"skip-reboot", no_argument, 0, 0},
+ {"verbose", no_argument, 0, 'v'},
+ {"version", no_argument, 0, 0},
{"disable-verity", no_argument, 0, 0},
{"disable-verification", no_argument, 0, 0},
{"header-version", required_argument, 0, 0},
@@ -1545,7 +1478,7 @@
serial = getenv("ANDROID_SERIAL");
while (1) {
- int c = getopt_long(argc, argv, "wub:k:n:r:t:s:S:lc:i:m:ha::", longopts, &longindex);
+ int c = getopt_long(argc, argv, "vwub:k:n:r:t:s:S:lc:i:m:ha::", longopts, &longindex);
if (c < 0) {
break;
}
@@ -1600,6 +1533,9 @@
case 'u':
erase_first = false;
break;
+ case 'v':
+ set_verbose();
+ break;
case 'w':
wants_wipe = true;
break;
@@ -1631,9 +1567,7 @@
} else if (strcmp("header-version", longopts[longindex].name) == 0) {
header_version = strtoul(optarg, nullptr, 0);
} else {
- fprintf(stderr, "Internal error in options processing for %s\n",
- longopts[longindex].name);
- return 1;
+ die("unknown option %s", longopts[longindex].name);
}
break;
default:
@@ -1742,9 +1676,6 @@
if (what == "bootloader") {
wants_reboot = false;
wants_reboot_bootloader = true;
- } else if (what == "emergency") {
- wants_reboot = false;
- wants_reboot_emergency = true;
} else {
syntax_error("unknown reboot target %s", what.c_str());
}
@@ -1847,12 +1778,8 @@
} else if (args.size() == 1 && (args[0] == "unlock" || args[0] == "lock" ||
args[0] == "unlock_critical" ||
args[0] == "lock_critical" ||
- args[0] == "get_unlock_ability" ||
- args[0] == "get_unlock_bootloader_nonce" ||
- args[0] == "lock_bootloader")) {
+ args[0] == "get_unlock_ability")) {
do_oem_command("flashing", &args);
- } else if (args.size() == 2 && args[0] == "unlock_bootloader") {
- do_bypass_unlock_command(&args);
} else {
syntax_error("unknown 'flashing' command %s", args[0].c_str());
}
@@ -1862,14 +1789,10 @@
}
if (wants_wipe) {
- fprintf(stderr, "wiping userdata...\n");
fb_queue_erase("userdata");
if (set_fbe_marker) {
- fprintf(stderr, "setting FBE marker...\n");
+ fprintf(stderr, "setting FBE marker on initial userdata...\n");
std::string initial_userdata_dir = create_fbemarker_tmpdir();
- if (initial_userdata_dir.empty()) {
- return 1;
- }
fb_perform_format(transport, "userdata", 1, "", "", initial_userdata_dir);
delete_fbemarker_tmpdir(initial_userdata_dir);
} else {
@@ -1878,7 +1801,6 @@
std::string cache_type;
if (fb_getvar(transport, "partition-type:cache", &cache_type) && !cache_type.empty()) {
- fprintf(stderr, "wiping cache...\n");
fb_queue_erase("cache");
fb_perform_format(transport, "cache", 1, "", "", "");
}
@@ -1892,9 +1814,6 @@
} else if (wants_reboot_bootloader) {
fb_queue_command("reboot-bootloader", "rebooting into bootloader");
fb_queue_wait_for_disconnect();
- } else if (wants_reboot_emergency) {
- fb_queue_command("reboot-emergency", "rebooting into emergency download (EDL) mode");
- fb_queue_wait_for_disconnect();
}
int status = fb_execute_queue(transport) ? EXIT_FAILURE : EXIT_SUCCESS;
diff --git a/fastboot/fastboot.h b/fastboot/fastboot.h
index a31057a..005ba5a 100644
--- a/fastboot/fastboot.h
+++ b/fastboot/fastboot.h
@@ -75,6 +75,7 @@
/* util stuff */
double now();
char* xstrdup(const char*);
+void set_verbose();
// These printf-like functions are implemented in terms of vsnprintf, so they
// use the same attribute for compile-time format string checking. On Windows,
@@ -90,6 +91,7 @@
#endif
void die(const char* fmt, ...) __attribute__((__noreturn__))
__attribute__((__format__(FASTBOOT_FORMAT_ARCHETYPE, 1, 2)));
+void verbose(const char* fmt, ...) __attribute__((__format__(FASTBOOT_FORMAT_ARCHETYPE, 1, 2)));
#undef FASTBOOT_FORMAT_ARCHETYPE
/* Current product */
diff --git a/fastboot/protocol.cpp b/fastboot/protocol.cpp
index c239861..133a2d0 100644
--- a/fastboot/protocol.cpp
+++ b/fastboot/protocol.cpp
@@ -75,18 +75,21 @@
}
if (!memcmp(status, "INFO", 4)) {
- fprintf(stderr,"(bootloader) %s\n", status + 4);
+ verbose("received INFO %s", status + 4);
+ fprintf(stderr, "(bootloader) %s\n", status + 4);
continue;
}
if (!memcmp(status, "OKAY", 4)) {
+ verbose("received OKAY %s", status + 4);
if (response) {
- strcpy(response, (char*) status + 4);
+ strcpy(response, status + 4);
}
return 0;
}
if (!memcmp(status, "FAIL", 4)) {
+ verbose("received FAIL %s", status + 4);
if (r > 4) {
g_error = android::base::StringPrintf("remote: %s", status + 4);
} else {
@@ -96,6 +99,7 @@
}
if (!memcmp(status, "DATA", 4) && size > 0){
+ verbose("received DATA %s", status + 4);
uint32_t dsize = strtol(status + 4, 0, 16);
if (dsize > size) {
g_error = android::base::StringPrintf("data size too large (%d)", dsize);
@@ -105,6 +109,7 @@
return dsize;
}
+ verbose("received unknown status code \"%4.4s\"", status);
g_error = "unknown status code";
transport->Close();
break;
@@ -124,6 +129,8 @@
response[0] = 0;
}
+ verbose("sending command \"%s\"", cmd.c_str());
+
if (transport->Write(cmd.c_str(), cmd.size()) != static_cast<int>(cmd.size())) {
g_error = android::base::StringPrintf("command write failed (%s)", strerror(errno));
transport->Close();
@@ -134,6 +141,8 @@
}
static int64_t _command_write_data(Transport* transport, const void* data, uint32_t size) {
+ verbose("sending data (%" PRIu32 " bytes)", size);
+
int64_t r = transport->Write(data, size);
if (r < 0) {
g_error = android::base::StringPrintf("data write failure (%s)", strerror(errno));
@@ -149,6 +158,8 @@
}
static int64_t _command_read_data(Transport* transport, void* data, uint32_t size) {
+ verbose("reading data (%" PRIu32 " bytes)", size);
+
int64_t r = transport->Read(data, size);
if (r < 0) {
g_error = android::base::StringPrintf("data read failure (%s)", strerror(errno));
diff --git a/fastboot/util.cpp b/fastboot/util.cpp
index fb085e7..140270f 100644
--- a/fastboot/util.cpp
+++ b/fastboot/util.cpp
@@ -35,6 +35,8 @@
#include "fastboot.h"
+static bool g_verbose = false;
+
double now() {
struct timeval tv;
gettimeofday(&tv, NULL);
@@ -44,13 +46,30 @@
void die(const char* fmt, ...) {
va_list ap;
va_start(ap, fmt);
- fprintf(stderr,"error: ");
+ fprintf(stderr, "fastboot: error: ");
vfprintf(stderr, fmt, ap);
- fprintf(stderr,"\n");
+ fprintf(stderr, "\n");
va_end(ap);
exit(EXIT_FAILURE);
}
+void set_verbose() {
+ g_verbose = true;
+}
+
+void verbose(const char* fmt, ...) {
+ if (!g_verbose) return;
+
+ if (*fmt != '\n') {
+ va_list ap;
+ va_start(ap, fmt);
+ fprintf(stderr, "fastboot: verbose: ");
+ vfprintf(stderr, fmt, ap);
+ va_end(ap);
+ }
+ fprintf(stderr, "\n");
+}
+
char* xstrdup(const char* s) {
char* result = strdup(s);
if (!result) die("out of memory");
diff --git a/fs_mgr/fs_mgr_fstab.cpp b/fs_mgr/fs_mgr_fstab.cpp
index 9d504d6..3fbef9f 100644
--- a/fs_mgr/fs_mgr_fstab.cpp
+++ b/fs_mgr/fs_mgr_fstab.cpp
@@ -33,6 +33,8 @@
#include "fs_mgr_priv.h"
+using android::base::StartsWith;
+
const std::string kDefaultAndroidDtDir("/proc/device-tree/firmware/android");
struct fs_mgr_flag_values {
@@ -443,6 +445,10 @@
LERROR << "dt_fstab: Failed to find device for partition " << dp->d_name;
return {};
}
+ if (!StartsWith(value, "/dev")) {
+ LERROR << "dt_fstab: Invalid device node for partition " << dp->d_name;
+ return {};
+ }
fstab_entry.push_back(value);
std::string mount_point;
diff --git a/healthd/Android.mk b/healthd/Android.mk
index 7792eaf..58661fe 100644
--- a/healthd/Android.mk
+++ b/healthd/Android.mk
@@ -74,9 +74,6 @@
ifeq ($(strip $(BOARD_CHARGER_NO_UI)),true)
LOCAL_CHARGER_NO_UI := true
endif
-ifdef BRILLO
-LOCAL_CHARGER_NO_UI := true
-endif
LOCAL_SRC_FILES := \
charger.cpp \
diff --git a/init/README.md b/init/README.md
index 5c2352b..59ddd77 100644
--- a/init/README.md
+++ b/init/README.md
@@ -161,6 +161,25 @@
Options are modifiers to services. They affect how and when init
runs the service.
+`capabilities <capability> [ <capability>\* ]`
+> Set capabilities when exec'ing this service. 'capability' should be a Linux
+ capability without the "CAP\_" prefix, like "NET\_ADMIN" or "SETPCAP". See
+ http://man7.org/linux/man-pages/man7/capabilities.7.html for a list of Linux
+ capabilities.
+
+`class <name> [ <name>\* ]`
+> Specify class names for the service. All services in a
+ named class may be started or stopped together. A service
+ is in the class "default" if one is not specified via the
+ class option. Additional classnames beyond the (required) first
+ one are used to group services.
+ The `animation` class should include all services necessary for both
+ boot animation and shutdown animation. As these services can be
+ launched very early during bootup and can run until the last stage
+ of shutdown, access to /data partition is not guaranteed. These
+ services can check files under /data but it should not keep files opened
+ and should work when /data is not available.
+
`console [<console>]`
> This service needs a console. The optional second parameter chooses a
specific console instead of the default. The default "/dev/console" can
@@ -176,9 +195,93 @@
> This service will not automatically start with its class.
It must be explicitly started by name.
+`file <path> <type>`
+> Open a file path and pass its fd to the launched process. _type_ must be
+ "r", "w" or "rw". For native executables see libcutils
+ android\_get\_control\_file().
+
+`group <groupname> [ <groupname>\* ]`
+> Change to 'groupname' before exec'ing this service. Additional
+ groupnames beyond the (required) first one are used to set the
+ supplemental groups of the process (via setgroups()).
+ Currently defaults to root. (??? probably should default to nobody)
+
+`interface <interface name> <instance name>`
+> Associates this service with a list of the HIDL services that it provides. The interface name
+ must be a fully-qualified name and not a value name. This is used to allow hwservicemanager to
+ lazily start services.
+ For example: interface vendor.foo.bar@1.0::IBaz default
+
+`ioprio <class> <priority>`
+> Sets the IO priority and IO priority class for this service via the SYS_ioprio_set syscall.
+ _class_ must be one of "rt", "be", or "idle". _priority_ must be an integer in the range 0 - 7.
+
+`keycodes <keycode> [ <keycode>\* ]`
+> Sets the keycodes that will trigger this service. If all of the keys corresponding to the passed
+ keycodes are pressed at once, the service will start. This is typically used to start the
+ bugreport service.
+
+`memcg.limit_in_bytes <value>`
+> Sets the child's memory.limit_in_bytes to the specified value (only if memcg is mounted),
+ which must be equal or greater than 0.
+
+`memcg.soft_limit_in_bytes <value>`
+> Sets the child's memory.soft_limit_in_bytes to the specified value (only if memcg is mounted),
+ which must be equal or greater than 0.
+
+`memcg.swappiness <value>`
+> Sets the child's memory.swappiness to the specified value (only if memcg is mounted),
+ which must be equal or greater than 0.
+
+`namespace <pid|mnt>`
+> Enter a new PID or mount namespace when forking the service.
+
+`oneshot`
+> Do not restart the service when it exits.
+
+`onrestart`
+> Execute a Command (see below) when service restarts.
+
+`oom_score_adjust <value>`
+> Sets the child's /proc/self/oom\_score\_adj to the specified value,
+ which must range from -1000 to 1000.
+
+`override`
+> Indicates that this service definition is meant to override a previous definition for a service
+ with the same name. This is typically meant for services on /odm to override those defined on
+ /vendor. The last service definition that init parses with this keyword is the service definition
+ will use for this service. Pay close attention to the order in which init.rc files are parsed,
+ since it has some peculiarities for backwards compatibility reasons. The 'imports' section of
+ this file has more details on the order.
+
+`priority <priority>`
+> Scheduling priority of the service process. This value has to be in range
+ -20 to 19. Default priority is 0. Priority is set via setpriority().
+
+`rlimit <resource> <cur> <max>`
+> This applies the given rlimit to the service. rlimits are inherited by child
+ processes, so this effectively applies the given rlimit to the process tree
+ started by this service.
+ It is parsed similarly to the setrlimit command specified below.
+
+`seclabel <seclabel>`
+> Change to 'seclabel' before exec'ing this service.
+ Primarily for use by services run from the rootfs, e.g. ueventd, adbd.
+ Services on the system partition can instead use policy-defined transitions
+ based on their file security context.
+ If not specified and no transition is defined in policy, defaults to the init context.
+
`setenv <name> <value>`
> Set the environment variable _name_ to _value_ in the launched process.
+`shutdown <shutdown_behavior>`
+> Set shutdown behavior of the service process. When this is not specified,
+ the service is killed during shutdown process by using SIGTERM and SIGKILL.
+ The service with shutdown_behavior of "critical" is not killed during shutdown
+ until shutdown times out. When shutdown times out, even services tagged with
+ "shutdown critical" will be killed. When the service tagged with "shutdown critical"
+ is not running when shut down starts, it will be started.
+
`socket <name> <type> <perm> [ <user> [ <group> [ <seclabel> ] ] ]`
> Create a unix domain socket named /dev/socket/_name_ and pass its fd to the
launched process. _type_ must be "dgram", "stream" or "seqpacket". User and
@@ -187,11 +290,6 @@
seclabel or computed based on the service executable file security context.
For native executables see libcutils android\_get\_control\_socket().
-`file <path> <type>`
-> Open a file path and pass its fd to the launched process. _type_ must be
- "r", "w" or "rw". For native executables see libcutils
- android\_get\_control\_file().
-
`user <username>`
> Change to 'username' before exec'ing this service.
Currently defaults to root. (??? probably should default to nobody)
@@ -208,88 +306,12 @@
As of Android O, processes can also request capabilities directly in their .rc
files. See the "capabilities" option below.
-`group <groupname> [ <groupname>\* ]`
-> Change to 'groupname' before exec'ing this service. Additional
- groupnames beyond the (required) first one are used to set the
- supplemental groups of the process (via setgroups()).
- Currently defaults to root. (??? probably should default to nobody)
-
-`capabilities <capability> [ <capability>\* ]`
-> Set capabilities when exec'ing this service. 'capability' should be a Linux
- capability without the "CAP\_" prefix, like "NET\_ADMIN" or "SETPCAP". See
- http://man7.org/linux/man-pages/man7/capabilities.7.html for a list of Linux
- capabilities.
-
-`setrlimit <resource> <cur> <max>`
-> This applies the given rlimit to the service. rlimits are inherited by child
- processes, so this effectively applies the given rlimit to the process tree
- started by this service.
- It is parsed similarly to the setrlimit command specified below.
-
-`seclabel <seclabel>`
-> Change to 'seclabel' before exec'ing this service.
- Primarily for use by services run from the rootfs, e.g. ueventd, adbd.
- Services on the system partition can instead use policy-defined transitions
- based on their file security context.
- If not specified and no transition is defined in policy, defaults to the init context.
-
-`oneshot`
-> Do not restart the service when it exits.
-
-`class <name> [ <name>\* ]`
-> Specify class names for the service. All services in a
- named class may be started or stopped together. A service
- is in the class "default" if one is not specified via the
- class option. Additional classnames beyond the (required) first
- one are used to group services.
-`animation class`
-> 'animation' class should include all services necessary for both
- boot animation and shutdown animation. As these services can be
- launched very early during bootup and can run until the last stage
- of shutdown, access to /data partition is not guaranteed. These
- services can check files under /data but it should not keep files opened
- and should work when /data is not available.
-
-`onrestart`
-> Execute a Command (see below) when service restarts.
-
`writepid <file> [ <file>\* ]`
> Write the child's pid to the given files when it forks. Meant for
cgroup/cpuset usage. If no files under /dev/cpuset/ are specified, but the
system property 'ro.cpuset.default' is set to a non-empty cpuset name (e.g.
'/foreground'), then the pid is written to file /dev/cpuset/_cpuset\_name_/tasks.
-`priority <priority>`
-> Scheduling priority of the service process. This value has to be in range
- -20 to 19. Default priority is 0. Priority is set via setpriority().
-
-`namespace <pid|mnt>`
-> Enter a new PID or mount namespace when forking the service.
-
-`oom_score_adjust <value>`
-> Sets the child's /proc/self/oom\_score\_adj to the specified value,
- which must range from -1000 to 1000.
-
-`memcg.swappiness <value>`
-> Sets the child's memory.swappiness to the specified value (only if memcg is mounted),
- which must be equal or greater than 0.
-
-`memcg.soft_limit_in_bytes <value>`
-> Sets the child's memory.soft_limit_in_bytes to the specified value (only if memcg is mounted),
- which must be equal or greater than 0.
-
-`memcg.limit_in_bytes <value>`
-> Sets the child's memory.limit_in_bytes to the specified value (only if memcg is mounted),
- which must be equal or greater than 0.
-
-`shutdown <shutdown_behavior>`
-> Set shutdown behavior of the service process. When this is not specified,
- the service is killed during shutdown process by using SIGTERM and SIGKILL.
- The service with shutdown_behavior of "critical" is not killed during shutdown
- until shutdown times out. When shutdown times out, even services tagged with
- "shutdown critical" will be killed. When the service tagged with "shutdown critical"
- is not running when shut down starts, it will be started.
-
Triggers
--------
diff --git a/init/reboot.cpp b/init/reboot.cpp
index 328164f..6f6e39f 100644
--- a/init/reboot.cpp
+++ b/init/reboot.cpp
@@ -458,10 +458,20 @@
if (kill_after_apps.count(s->name())) s->Stop();
}
// 4. sync, try umount, and optionally run fsck for user shutdown
- sync();
+ {
+ Timer sync_timer;
+ LOG(INFO) << "sync() before umount...";
+ sync();
+ LOG(INFO) << "sync() before umount took" << sync_timer;
+ }
UmountStat stat = TryUmountAndFsck(runFsck, shutdown_timeout - t.duration());
// Follow what linux shutdown is doing: one more sync with little bit delay
- sync();
+ {
+ Timer sync_timer;
+ LOG(INFO) << "sync() after umount...";
+ sync();
+ LOG(INFO) << "sync() after umount took" << sync_timer;
+ }
if (!is_thermal_shutdown) std::this_thread::sleep_for(100ms);
LogShutdownTime(stat, &t);
// Reboot regardless of umount status. If umount fails, fsck after reboot will fix it.
diff --git a/init/service.cpp b/init/service.cpp
index 8130e73..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 << "'";
}
@@ -678,29 +678,29 @@
{"console", {0, 1, &Service::ParseConsole}},
{"critical", {0, 0, &Service::ParseCritical}},
{"disabled", {0, 0, &Service::ParseDisabled}},
+ {"file", {2, 2, &Service::ParseFile}},
{"group", {1, NR_SVC_SUPP_GIDS + 1, &Service::ParseGroup}},
{"interface", {2, 2, &Service::ParseInterface}},
{"ioprio", {2, 2, &Service::ParseIoprio}},
- {"priority", {1, 1, &Service::ParsePriority}},
{"keycodes", {1, kMax, &Service::ParseKeycodes}},
- {"oneshot", {0, 0, &Service::ParseOneshot}},
- {"onrestart", {1, kMax, &Service::ParseOnrestart}},
- {"override", {0, 0, &Service::ParseOverride}},
- {"oom_score_adjust",
- {1, 1, &Service::ParseOomScoreAdjust}},
- {"memcg.swappiness",
- {1, 1, &Service::ParseMemcgSwappiness}},
- {"memcg.soft_limit_in_bytes",
- {1, 1, &Service::ParseMemcgSoftLimitInBytes}},
{"memcg.limit_in_bytes",
{1, 1, &Service::ParseMemcgLimitInBytes}},
+ {"memcg.soft_limit_in_bytes",
+ {1, 1, &Service::ParseMemcgSoftLimitInBytes}},
+ {"memcg.swappiness",
+ {1, 1, &Service::ParseMemcgSwappiness}},
{"namespace", {1, 2, &Service::ParseNamespace}},
+ {"oneshot", {0, 0, &Service::ParseOneshot}},
+ {"onrestart", {1, kMax, &Service::ParseOnrestart}},
+ {"oom_score_adjust",
+ {1, 1, &Service::ParseOomScoreAdjust}},
+ {"override", {0, 0, &Service::ParseOverride}},
+ {"priority", {1, 1, &Service::ParsePriority}},
{"rlimit", {3, 3, &Service::ParseProcessRlimit}},
{"seclabel", {1, 1, &Service::ParseSeclabel}},
{"setenv", {2, 2, &Service::ParseSetenv}},
{"shutdown", {1, 1, &Service::ParseShutdown}},
{"socket", {3, 6, &Service::ParseSocket}},
- {"file", {2, 2, &Service::ParseFile}},
{"user", {1, 1, &Service::ParseUser}},
{"writepid", {1, kMax, &Service::ParseWritepid}},
};
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/libbacktrace/include/backtrace/BacktraceMap.h b/libbacktrace/include/backtrace/BacktraceMap.h
index 473d195..c94cad1 100644
--- a/libbacktrace/include/backtrace/BacktraceMap.h
+++ b/libbacktrace/include/backtrace/BacktraceMap.h
@@ -40,6 +40,10 @@
// Special flag to indicate a map is in /dev/. However, a map in
// /dev/ashmem/... does not set this flag.
static constexpr int PROT_DEVICE_MAP = 0x8000;
+// Special flag to indicate that this map represents an elf file
+// created by ART for use with the gdb jit debug interface.
+// This should only ever appear in offline maps data.
+static constexpr int PROT_JIT_SYMFILE_MAP = 0x4000;
struct backtrace_map_t {
uint64_t start = 0;
diff --git a/libcutils/fs_config.cpp b/libcutils/fs_config.cpp
index f6f7128..0f2b460 100644
--- a/libcutils/fs_config.cpp
+++ b/libcutils/fs_config.cpp
@@ -122,6 +122,12 @@
{odm_conf_file, odm_conf_dir},
};
+// Do not use android_files to grant Linux capabilities. Use ambient capabilities in their
+// associated init.rc file instead. See https://source.android.com/devices/tech/config/ambient.
+
+// Do not place any new vendor/, data/vendor/, etc entries in android_files.
+// Vendor entries should be done via a vendor or device specific config.fs.
+// See https://source.android.com/devices/tech/config/filesystem#using-file-system-capabilities
static const struct fs_path_config android_files[] = {
// clang-format off
{ 00644, AID_SYSTEM, AID_SYSTEM, 0, "data/app/*" },
@@ -185,24 +191,6 @@
// Support FIFO scheduling mode in SurfaceFlinger.
{ 00755, AID_SYSTEM, AID_GRAPHICS, CAP_MASK_LONG(CAP_SYS_NICE),
"system/bin/surfaceflinger" },
-
- // Support hostapd administering a network interface.
- { 00755, AID_WIFI, AID_WIFI, CAP_MASK_LONG(CAP_NET_ADMIN) |
- CAP_MASK_LONG(CAP_NET_RAW),
- "vendor/bin/hostapd" },
-
- // Support Bluetooth legacy hal accessing /sys/class/rfkill
- // Support RT scheduling in Bluetooth
- { 00700, AID_BLUETOOTH, AID_BLUETOOTH, CAP_MASK_LONG(CAP_NET_ADMIN) |
- CAP_MASK_LONG(CAP_SYS_NICE),
- "vendor/bin/hw/android.hardware.bluetooth@1.0-service" },
-
- // Support wifi_hal_legacy administering a network interface.
- { 00755, AID_WIFI, AID_WIFI, CAP_MASK_LONG(CAP_NET_ADMIN) |
- CAP_MASK_LONG(CAP_NET_RAW) |
- CAP_MASK_LONG(CAP_SYS_MODULE),
- "vendor/bin/hw/android.hardware.wifi@1.0-service" },
-
// generic defaults
{ 00755, AID_ROOT, AID_ROOT, 0, "bin/*" },
{ 00640, AID_ROOT, AID_SHELL, 0, "fstab.*" },
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/libmemunreachable/Android.bp b/libmemunreachable/Android.bp
index caca377..f872d0f 100644
--- a/libmemunreachable/Android.bp
+++ b/libmemunreachable/Android.bp
@@ -88,7 +88,6 @@
cc_test {
name: "memunreachable_binder_test",
defaults: ["libmemunreachable_defaults"],
- test_suites: ["vts"],
srcs: [
"tests/Binder_test.cpp",
],
diff --git a/libunwindstack/Android.bp b/libunwindstack/Android.bp
index 7b8111c..6868f18 100644
--- a/libunwindstack/Android.bp
+++ b/libunwindstack/Android.bp
@@ -47,6 +47,8 @@
srcs: [
"ArmExidx.cpp",
+ "DexFile.cpp",
+ "DexFiles.cpp",
"DwarfCfa.cpp",
"DwarfEhFrameWithHdr.cpp",
"DwarfMemory.cpp",
@@ -85,11 +87,13 @@
},
vendor: {
cflags: ["-DNO_LIBDEXFILE_SUPPORT"],
- exclude_static_libs: ["libunwindstack_dex"],
+ exclude_srcs: [
+ "DexFile.cpp",
+ "DexFiles.cpp",
+ ],
exclude_shared_libs: ["libdexfile"],
},
},
- whole_static_libs: ["libunwindstack_dex"],
arch: {
x86: {
@@ -114,79 +118,9 @@
],
}
-// Isolate the dex file processing into a separate library. Currently,
-// it is necessary to add art include directories directly, which also
-// adds the art elf.h file in the include path, overriding the system one.
-// Work to isolate libdexfile is b/72216369.
-cc_library_static {
- name: "libunwindstack_dex",
- vendor_available: false,
- defaults: ["libunwindstack_flags"],
-
- cflags: [
- "-Wexit-time-destructors",
- ],
-
- srcs: [
- "DexFile.cpp",
- "DexFiles.cpp",
- ],
- target: {
- // Always disable optimizations for host to make it easier to debug.
- host: {
- cflags: [
- "-O0",
- "-g",
- ],
- },
- },
-
- shared_libs: [
- "libbase",
- "libdexfile",
- ],
- local_include_dirs: ["include"],
- allow_undefined_symbols: true,
-
- // libdexfile will eventually properly export headers, for now include
- // these directly.
- include_dirs: [
- "art/runtime",
- ],
-}
-
//-------------------------------------------------------------------------
// Unit Tests
//-------------------------------------------------------------------------
-cc_test_library {
- name: "libunwindstack_dex_test",
- vendor_available: false,
- defaults: ["libunwindstack_flags"],
-
- shared: {
- enabled: false,
- },
-
- srcs: [
- "tests/DexFileTest.cpp",
- "tests/DexFilesTest.cpp",
- ],
- local_include_dirs: ["include"],
- allow_undefined_symbols: true,
-
- shared_libs: [
- "libbase",
- "libunwindstack",
- "libdexfile",
- ],
-
- // libdexfile will eventually properly export headers, for now include
- // these directly.
- include_dirs: [
- "art/runtime",
- ],
-}
-
cc_test {
name: "libunwindstack_test",
defaults: ["libunwindstack_flags"],
@@ -194,6 +128,8 @@
srcs: [
"tests/ArmExidxDecodeTest.cpp",
"tests/ArmExidxExtractTest.cpp",
+ "tests/DexFileTest.cpp",
+ "tests/DexFilesTest.cpp",
"tests/DwarfCfaLogTest.cpp",
"tests/DwarfCfaTest.cpp",
"tests/DwarfDebugFrameTest.cpp",
@@ -243,14 +179,13 @@
"liblog",
"liblzma",
"libunwindstack",
+ "libdexfile",
],
static_libs: [
"libgmock",
],
- whole_static_libs: ["libunwindstack_dex_test"],
-
data: [
"tests/files/elf32.xz",
"tests/files/elf64.xz",
@@ -260,6 +195,7 @@
"tests/files/offline/eh_frame_hdr_begin_x86_64/*",
"tests/files/offline/jit_debug_arm/*",
"tests/files/offline/jit_debug_x86/*",
+ "tests/files/offline/jit_map_arm/*",
"tests/files/offline/gnu_debugdata_arm/*",
"tests/files/offline/straddle_arm/*",
"tests/files/offline/straddle_arm64/*",
diff --git a/libunwindstack/Maps.cpp b/libunwindstack/Maps.cpp
index 4c16212..e1a1a71 100644
--- a/libunwindstack/Maps.cpp
+++ b/libunwindstack/Maps.cpp
@@ -25,6 +25,7 @@
#include <android-base/unique_fd.h>
+#include <algorithm>
#include <cctype>
#include <memory>
#include <string>
@@ -209,6 +210,11 @@
maps_.push_back(map_info);
}
+void Maps::Sort() {
+ std::sort(maps_.begin(), maps_.end(),
+ [](const MapInfo* a, const MapInfo* b) { return a->start < b->start; });
+}
+
Maps::~Maps() {
for (auto& map : maps_) {
delete map;
diff --git a/libunwindstack/Unwinder.cpp b/libunwindstack/Unwinder.cpp
index 94edb1c..9a6c6df 100644
--- a/libunwindstack/Unwinder.cpp
+++ b/libunwindstack/Unwinder.cpp
@@ -29,6 +29,7 @@
#include <unwindstack/Elf.h>
#include <unwindstack/JitDebug.h>
#include <unwindstack/MapInfo.h>
+#include <unwindstack/Maps.h>
#include <unwindstack/Unwinder.h>
#if !defined(NO_LIBDEXFILE_SUPPORT)
@@ -61,7 +62,9 @@
frame->map_offset = info->offset;
frame->map_load_bias = info->load_bias;
frame->map_flags = info->flags;
- frame->map_name = info->name;
+ if (resolve_names_) {
+ frame->map_name = info->name;
+ }
frame->rel_pc = dex_pc - info->start;
} else {
frame->rel_pc = dex_pc;
@@ -96,7 +99,9 @@
return;
}
- frame->map_name = map_info->name;
+ if (resolve_names_) {
+ frame->map_name = map_info->name;
+ }
frame->map_offset = map_info->offset;
frame->map_start = map_info->start;
frame->map_end = map_info->end;
@@ -138,26 +143,31 @@
uint64_t cur_sp = regs_->sp();
MapInfo* map_info = maps_->Find(regs_->pc());
- uint64_t rel_pc;
uint64_t pc_adjustment = 0;
uint64_t step_pc;
+ uint64_t rel_pc;
Elf* elf;
if (map_info == nullptr) {
- rel_pc = regs_->pc();
- step_pc = rel_pc;
+ step_pc = regs_->pc();
+ rel_pc = step_pc;
last_error_.code = ERROR_INVALID_MAP;
} else {
if (ShouldStop(map_suffixes_to_ignore, map_info->name)) {
break;
}
elf = map_info->GetElf(process_memory_, true);
- rel_pc = elf->GetRelPc(regs_->pc(), map_info);
+ step_pc = regs_->pc();
+ rel_pc = elf->GetRelPc(step_pc, map_info);
+ // Everyone except elf data in gdb jit debug maps uses the relative pc.
+ if (!(map_info->flags & MAPS_FLAGS_JIT_SYMFILE_MAP)) {
+ step_pc = rel_pc;
+ }
if (adjust_pc) {
pc_adjustment = regs_->GetPcAdjustment(rel_pc, elf);
} else {
pc_adjustment = 0;
}
- step_pc = rel_pc - pc_adjustment;
+ step_pc -= pc_adjustment;
// If the pc is in an invalid elf file, try and get an Elf object
// using the jit debug information.
diff --git a/libunwindstack/include/unwindstack/Maps.h b/libunwindstack/include/unwindstack/Maps.h
index 17a2d28..74e5c47 100644
--- a/libunwindstack/include/unwindstack/Maps.h
+++ b/libunwindstack/include/unwindstack/Maps.h
@@ -30,6 +30,10 @@
// Special flag to indicate a map is in /dev/. However, a map in
// /dev/ashmem/... does not set this flag.
static constexpr int MAPS_FLAGS_DEVICE_MAP = 0x8000;
+// Special flag to indicate that this map represents an elf file
+// created by ART for use with the gdb jit debug interface.
+// This should only ever appear in offline maps data.
+static constexpr int MAPS_FLAGS_JIT_SYMFILE_MAP = 0x4000;
class Maps {
public:
@@ -45,6 +49,8 @@
void Add(uint64_t start, uint64_t end, uint64_t offset, uint64_t flags, const std::string& name,
uint64_t load_bias);
+ void Sort();
+
typedef std::vector<MapInfo*>::iterator iterator;
iterator begin() { return maps_.begin(); }
iterator end() { return maps_.end(); }
diff --git a/libunwindstack/tests/UnwindOfflineTest.cpp b/libunwindstack/tests/UnwindOfflineTest.cpp
index 8cb640f..2b8f0c2 100644
--- a/libunwindstack/tests/UnwindOfflineTest.cpp
+++ b/libunwindstack/tests/UnwindOfflineTest.cpp
@@ -18,6 +18,7 @@
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
+#include <sys/mman.h>
#include <unistd.h>
#include <gtest/gtest.h>
@@ -1070,4 +1071,44 @@
EXPECT_EQ(0xcd4ff960U, unwinder.frames()[24].sp);
}
+TEST_F(UnwindOfflineTest, jit_map_arm) {
+ Init("jit_map_arm/", ARCH_ARM);
+
+ maps_->Add(0xd025c788, 0xd025c9f0, 0, PROT_READ | PROT_EXEC | MAPS_FLAGS_JIT_SYMFILE_MAP,
+ "jit_map0.so", 0);
+ maps_->Add(0xd025cd98, 0xd025cff4, 0, PROT_READ | PROT_EXEC | MAPS_FLAGS_JIT_SYMFILE_MAP,
+ "jit_map1.so", 0);
+ maps_->Sort();
+
+ Unwinder unwinder(128, maps_.get(), regs_.get(), process_memory_);
+ unwinder.Unwind();
+
+ std::string frame_info(DumpFrames(unwinder));
+ ASSERT_EQ(6U, unwinder.NumFrames()) << "Unwind:\n" << frame_info;
+ EXPECT_EQ(
+ " #00 pc 00000000 jit_map0.so "
+ "(com.example.simpleperf.simpleperfexamplewithnative.MixActivity.access$000)\n"
+ " #01 pc 0000003d jit_map1.so "
+ "(com.example.simpleperf.simpleperfexamplewithnative.MixActivity$1.run+60)\n"
+ " #02 pc 004135bb libart.so (art_quick_osr_stub+42)\n"
+
+ " #03 pc 003851dd libart.so (_ZN3art6Thread14CreateCallbackEPv+868)\n"
+ " #04 pc 00062925 libc.so (_ZL15__pthread_startPv+22)\n"
+ " #05 pc 0001de39 libc.so (__start_thread+24)\n",
+ frame_info);
+
+ EXPECT_EQ(0xd025c788U, unwinder.frames()[0].pc);
+ EXPECT_EQ(0xcd4ff140U, unwinder.frames()[0].sp);
+ EXPECT_EQ(0xd025cdd5U, unwinder.frames()[1].pc);
+ EXPECT_EQ(0xcd4ff140U, unwinder.frames()[1].sp);
+ EXPECT_EQ(0xe4a755bbU, unwinder.frames()[2].pc);
+ EXPECT_EQ(0xcd4ff160U, unwinder.frames()[2].sp);
+ EXPECT_EQ(0xe49e71ddU, unwinder.frames()[3].pc);
+ EXPECT_EQ(0xcd4ff8e8U, unwinder.frames()[3].sp);
+ EXPECT_EQ(0xe7df3925U, unwinder.frames()[4].pc);
+ EXPECT_EQ(0xcd4ff958U, unwinder.frames()[4].sp);
+ EXPECT_EQ(0xe7daee39U, unwinder.frames()[5].pc);
+ EXPECT_EQ(0xcd4ff960U, unwinder.frames()[5].sp);
+}
+
} // namespace unwindstack
diff --git a/libunwindstack/tests/UnwinderTest.cpp b/libunwindstack/tests/UnwinderTest.cpp
index b38fb5f..2428f68 100644
--- a/libunwindstack/tests/UnwinderTest.cpp
+++ b/libunwindstack/tests/UnwinderTest.cpp
@@ -221,7 +221,7 @@
EXPECT_EQ(0x10000U, frame->sp);
EXPECT_EQ("", frame->function_name);
EXPECT_EQ(0U, frame->function_offset);
- EXPECT_EQ("/system/fake/libc.so", frame->map_name);
+ EXPECT_EQ("", frame->map_name);
EXPECT_EQ(0U, frame->map_offset);
EXPECT_EQ(0x1000U, frame->map_start);
EXPECT_EQ(0x8000U, frame->map_end);
@@ -235,7 +235,7 @@
EXPECT_EQ(0x10010U, frame->sp);
EXPECT_EQ("", frame->function_name);
EXPECT_EQ(0U, frame->function_offset);
- EXPECT_EQ("/system/fake/libc.so", frame->map_name);
+ EXPECT_EQ("", frame->map_name);
EXPECT_EQ(0U, frame->map_offset);
EXPECT_EQ(0x1000U, frame->map_start);
EXPECT_EQ(0x8000U, frame->map_end);
@@ -249,7 +249,7 @@
EXPECT_EQ(0x10020U, frame->sp);
EXPECT_EQ("", frame->function_name);
EXPECT_EQ(0U, frame->function_offset);
- EXPECT_EQ("/system/fake/libc.so", frame->map_name);
+ EXPECT_EQ("", frame->map_name);
EXPECT_EQ(0U, frame->map_offset);
EXPECT_EQ(0x1000U, frame->map_start);
EXPECT_EQ(0x8000U, frame->map_end);
diff --git a/libunwindstack/tests/files/offline/jit_map_arm/jit_map0.so b/libunwindstack/tests/files/offline/jit_map_arm/jit_map0.so
new file mode 100644
index 0000000..e667883
--- /dev/null
+++ b/libunwindstack/tests/files/offline/jit_map_arm/jit_map0.so
Binary files differ
diff --git a/libunwindstack/tests/files/offline/jit_map_arm/jit_map1.so b/libunwindstack/tests/files/offline/jit_map_arm/jit_map1.so
new file mode 100644
index 0000000..9a1d714
--- /dev/null
+++ b/libunwindstack/tests/files/offline/jit_map_arm/jit_map1.so
Binary files differ
diff --git a/libunwindstack/tests/files/offline/jit_map_arm/libart.so b/libunwindstack/tests/files/offline/jit_map_arm/libart.so
new file mode 100644
index 0000000..09ba495
--- /dev/null
+++ b/libunwindstack/tests/files/offline/jit_map_arm/libart.so
Binary files differ
diff --git a/libunwindstack/tests/files/offline/jit_map_arm/libc.so b/libunwindstack/tests/files/offline/jit_map_arm/libc.so
new file mode 100644
index 0000000..39c9025
--- /dev/null
+++ b/libunwindstack/tests/files/offline/jit_map_arm/libc.so
Binary files differ
diff --git a/libunwindstack/tests/files/offline/jit_map_arm/maps.txt b/libunwindstack/tests/files/offline/jit_map_arm/maps.txt
new file mode 100644
index 0000000..5aaec54
--- /dev/null
+++ b/libunwindstack/tests/files/offline/jit_map_arm/maps.txt
@@ -0,0 +1,2 @@
+e466e000-e4ae8000 r-xp 0 00:00 0 libart.so
+e7d91000-e7e31000 r-xp 0 00:00 0 libc.so
diff --git a/libunwindstack/tests/files/offline/jit_map_arm/regs.txt b/libunwindstack/tests/files/offline/jit_map_arm/regs.txt
new file mode 100644
index 0000000..0b51814
--- /dev/null
+++ b/libunwindstack/tests/files/offline/jit_map_arm/regs.txt
@@ -0,0 +1,16 @@
+r0: e814103c
+r1: 12dcf218
+r2: 1a90df75
+r3: ffffffbf
+r4: 0
+r5: 12dc0800
+r6: 12dcf218
+r7: 1a90df75
+r8: 0
+r9: dd23cc00
+r10: 1c
+r11: cd4ff16c
+ip: 0
+sp: cd4ff140
+lr: d025cdd7
+pc: d025c788
diff --git a/libunwindstack/tests/files/offline/jit_map_arm/stack.data b/libunwindstack/tests/files/offline/jit_map_arm/stack.data
new file mode 100644
index 0000000..fb8feeb
--- /dev/null
+++ b/libunwindstack/tests/files/offline/jit_map_arm/stack.data
Binary files differ
diff --git a/libutils/Android.bp b/libutils/Android.bp
index a4fc4b4..0d7925a 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 e8f1c51..230e970 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/lmkd.c b/lmkd/lmkd.c
index ee2f343..937a218 100644
--- a/lmkd/lmkd.c
+++ b/lmkd/lmkd.c
@@ -18,8 +18,10 @@
#include <errno.h>
#include <inttypes.h>
+#include <pwd.h>
#include <sched.h>
#include <signal.h>
+#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
#include <sys/cdefs.h>
@@ -75,8 +77,8 @@
#define ARRAY_SIZE(x) (sizeof(x) / sizeof(*(x)))
#define EIGHT_MEGA (1 << 23)
-#define STRINGIFY(x) STRINGIFY_INTERNAL(x)
-#define STRINGIFY_INTERNAL(x) #x
+/* Defined as ProcessList.SYSTEM_ADJ in ProcessList.java */
+#define SYSTEM_ADJ (-900)
/* default to old in-kernel interface if no memory pressure events */
static int use_inkernel_interface = 1;
@@ -279,24 +281,32 @@
return 0;
}
-static void writefilestring(const char *path, char *s) {
+/*
+ * Write a string to a file.
+ * Returns false if the file does not exist.
+ */
+static bool writefilestring(const char *path, const char *s,
+ bool err_if_missing) {
int fd = open(path, O_WRONLY | O_CLOEXEC);
- int len = strlen(s);
- int ret;
+ ssize_t len = strlen(s);
+ ssize_t ret;
if (fd < 0) {
- ALOGE("Error opening %s; errno=%d", path, errno);
- return;
+ if (err_if_missing) {
+ ALOGE("Error opening %s; errno=%d", path, errno);
+ }
+ return false;
}
- ret = write(fd, s, len);
+ ret = TEMP_FAILURE_RETRY(write(fd, s, len));
if (ret < 0) {
ALOGE("Error writing %s; errno=%d", path, errno);
} else if (ret < len) {
- ALOGE("Short write on %s; length=%d", path, ret);
+ ALOGE("Short write on %s; length=%zd", path, ret);
}
close(fd);
+ return true;
}
static void cmd_procprio(LMKD_CTRL_PACKET packet) {
@@ -305,6 +315,8 @@
char val[20];
int soft_limit_mult;
struct lmk_procprio params;
+ bool is_system_server;
+ struct passwd *pwdrec;
lmkd_pack_get_procprio(packet, ¶ms);
@@ -316,7 +328,12 @@
snprintf(path, sizeof(path), "/proc/%d/oom_score_adj", params.pid);
snprintf(val, sizeof(val), "%d", params.oomadj);
- writefilestring(path, val);
+ if (!writefilestring(path, val, false)) {
+ ALOGW("Failed to open %s; errno=%d: process %d might have been killed",
+ path, errno, params.pid);
+ /* If this file does not exist the process is dead. */
+ return;
+ }
if (use_inkernel_interface)
return;
@@ -353,7 +370,15 @@
"/dev/memcg/apps/uid_%d/pid_%d/memory.soft_limit_in_bytes",
params.uid, params.pid);
snprintf(val, sizeof(val), "%d", soft_limit_mult * EIGHT_MEGA);
- writefilestring(path, val);
+
+ /*
+ * system_server process has no memcg under /dev/memcg/apps but should be
+ * registered with lmkd. This is the best way so far to identify it.
+ */
+ is_system_server = (params.oomadj == SYSTEM_ADJ &&
+ (pwdrec = getpwnam("system")) != NULL &&
+ params.uid == pwdrec->pw_uid);
+ writefilestring(path, val, !is_system_server);
procp = pid_lookup(params.pid);
if (!procp) {
@@ -420,8 +445,8 @@
strlcat(killpriostr, val, sizeof(killpriostr));
}
- writefilestring(INKERNEL_MINFREE_PATH, minfreestr);
- writefilestring(INKERNEL_ADJ_PATH, killpriostr);
+ writefilestring(INKERNEL_MINFREE_PATH, minfreestr, true);
+ writefilestring(INKERNEL_ADJ_PATH, killpriostr, true);
}
}
@@ -558,10 +583,10 @@
#ifdef LMKD_LOG_STATS
static void memory_stat_parse_line(char *line, struct memory_stat *mem_st) {
- char key[LINE_MAX + 1];
+ char key[LINE_MAX];
int64_t value;
- sscanf(line, "%" STRINGIFY(LINE_MAX) "s %" SCNd64 "", key, &value);
+ sscanf(line,"%s %" SCNd64 "", key, &value);
if (strcmp(key, "total_") < 0) {
return;
@@ -725,7 +750,7 @@
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",
+ " to free %ldkB because system is under %s memory pressure (min_oom_adj=%d)\n",
taskname, pid, uid, procp->oomadj, tasksize * page_k,
level_name[level], min_score_adj);
pid_remove(pid);
diff --git a/mkbootimg/OWNERS b/mkbootimg/OWNERS
new file mode 100644
index 0000000..39448cf
--- /dev/null
+++ b/mkbootimg/OWNERS
@@ -0,0 +1 @@
+tbao@google.com
diff --git a/storaged/OWNERS b/storaged/OWNERS
index 7445270..c6feee8 100644
--- a/storaged/OWNERS
+++ b/storaged/OWNERS
@@ -1 +1,2 @@
jinqian@google.com
+salyzyn@google.com