[automerger skipped] Merge changes from topic "generic_by_name" into pi-dev
am: 34de3c84fe -s ours
Change-Id: I4bbcfafd21370d14d796fff341d5bf83b91fff95
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..99de54e 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",
+
+ 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",
+ ],
+ test_suites: ["device-tests"],
+}
+
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 c791c7b..76ca19a 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, ...) {
@@ -131,12 +132,21 @@
{
D("adb: online");
t->online = 1;
+ t->SetConnectionEstablished(true);
}
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
@@ -248,7 +258,7 @@
<< connection_str.length() << ")";
}
- cp->payload = std::move(connection_str);
+ cp->payload.assign(connection_str.begin(), connection_str.end());
cp->msg.data_length = cp->payload.size();
send_packet(cp, t);
@@ -317,13 +327,11 @@
}
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);
+ std::string banner(p->payload.begin(), p->payload.end());
+ parse_banner(banner, t);
#if ADB_HOST
handle_online(t);
@@ -349,19 +357,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;
@@ -370,14 +365,16 @@
switch (p->msg.arg0) {
#if ADB_HOST
case ADB_AUTH_TOKEN:
- if (t->GetConnectionState() == kCsOffline) {
- t->SetConnectionState(kCsUnauthorized);
+ if (t->GetConnectionState() != kCsAuthorizing) {
+ t->SetConnectionState(kCsAuthorizing);
}
send_auth_response(p->payload.data(), p->msg.data_length, t);
break;
#else
- case ADB_AUTH_SIGNATURE:
- if (adbd_auth_verify(t->token, sizeof(t->token), p->payload)) {
+ case ADB_AUTH_SIGNATURE: {
+ // TODO: Switch to string_view.
+ std::string signature(p->payload.begin(), p->payload.end());
+ if (adbd_auth_verify(t->token, sizeof(t->token), signature)) {
adbd_auth_verified(t);
t->failed_auth_attempts = 0;
} else {
@@ -385,6 +382,7 @@
send_auth_request(t);
}
break;
+ }
case ADB_AUTH_RSAPUBLICKEY:
adbd_auth_confirm_key(p->payload.data(), p->msg.data_length, t);
@@ -399,7 +397,9 @@
case A_OPEN: /* OPEN(local-id, 0, "destination") */
if (t->online && p->msg.arg0 != 0 && p->msg.arg1 == 0) {
- asocket* s = create_local_service_socket(p->payload.c_str(), t);
+ // TODO: Switch to string_view.
+ std::string address(p->payload.begin(), p->payload.end());
+ asocket* s = create_local_service_socket(address.c_str(), t);
if (s == nullptr) {
send_close(0, p->msg.arg0, t);
} else {
@@ -1103,14 +1103,11 @@
if (!strcmp(service, "reconnect-offline")) {
std::string response;
close_usb_devices([&response](const atransport* transport) {
- switch (transport->GetConnectionState()) {
- case kCsOffline:
- case kCsUnauthorized:
- response += "reconnecting " + transport->serial_name() + "\n";
- return true;
- default:
- return false;
+ if (!ConnectionStateIsOnline(transport->GetConnectionState())) {
+ response += "reconnecting " + transport->serial_name() + "\n";
+ return true;
}
+ return false;
});
if (!response.empty()) {
response.resize(response.size() - 1);
diff --git a/adb/adb.h b/adb/adb.h
index 65b5fc0..ede55da 100644
--- a/adb/adb.h
+++ b/adb/adb.h
@@ -28,6 +28,7 @@
#include "adb_trace.h"
#include "fdevent.h"
#include "socket.h"
+#include "types.h"
#include "usb.h"
constexpr size_t MAX_PAYLOAD_V1 = 4 * 1024;
@@ -63,20 +64,6 @@
using TransportId = uint64_t;
class atransport;
-struct amessage {
- uint32_t command; /* command identifier constant */
- uint32_t arg0; /* first argument */
- uint32_t arg1; /* second argument */
- uint32_t data_length; /* length of payload (0 is allowed) */
- uint32_t data_check; /* checksum of data payload */
- uint32_t magic; /* command ^ 0xffffffff */
-};
-
-struct apacket {
- amessage msg;
- std::string payload;
-};
-
uint32_t calculate_apacket_checksum(const apacket* packet);
/* the adisconnect structure is used to record a callback that
@@ -108,16 +95,33 @@
enum ConnectionState {
kCsAny = -1,
- kCsOffline = 0,
+
+ kCsConnecting = 0, // Haven't received a response from the device yet.
+ kCsAuthorizing, // Authorizing with keys from ADB_VENDOR_KEYS.
+ kCsUnauthorized, // ADB_VENDOR_KEYS exhausted, fell back to user prompt.
+ kCsNoPerm, // Insufficient permissions to communicate with the device.
+ kCsOffline,
+
kCsBootloader,
kCsDevice,
kCsHost,
kCsRecovery,
- kCsNoPerm, // Insufficient permissions to communicate with the device.
kCsSideload,
- kCsUnauthorized,
};
+inline bool ConnectionStateIsOnline(ConnectionState state) {
+ switch (state) {
+ case kCsBootloader:
+ case kCsDevice:
+ case kCsHost:
+ case kCsRecovery:
+ case kCsSideload:
+ return true;
+ default:
+ return false;
+ }
+}
+
void print_packet(const char* label, apacket* p);
// These use the system (v)fprintf, not the adb prefixed ones defined in sysdeps.h, so they
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 98%
rename from adb/adb_auth_host.cpp
rename to adb/client/auth.cpp
index c3aef16..0f4dd33 100644
--- a/adb/adb_auth_host.cpp
+++ b/adb/client/auth.cpp
@@ -454,10 +454,8 @@
p->msg.command = A_AUTH;
p->msg.arg0 = ADB_AUTH_RSAPUBLICKEY;
- p->payload = std::move(key);
-
// adbd expects a null-terminated string.
- p->payload.push_back('\0');
+ p->payload.assign(key.data(), key.data() + key.size() + 1);
p->msg.data_length = p->payload.size();
send_packet(p, t);
}
@@ -466,6 +464,7 @@
std::shared_ptr<RSA> key = t->NextKey();
if (key == nullptr) {
// No more private keys to try, send the public key.
+ t->SetConnectionState(kCsUnauthorized);
send_auth_publickey(t);
return;
}
@@ -482,7 +481,7 @@
p->msg.command = A_AUTH;
p->msg.arg0 = ADB_AUTH_SIGNATURE;
- p->payload = std::move(result);
+ p->payload.assign(result.begin(), result.end());
p->msg.data_length = p->payload.size();
send_packet(p, t);
}
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/client/main.cpp b/adb/client/main.cpp
index 31cb853..44ed3a2 100644
--- a/adb/client/main.cpp
+++ b/adb/client/main.cpp
@@ -117,6 +117,7 @@
atexit(adb_server_cleanup);
init_transport_registration();
+ init_reconnect_handler();
init_mdns_transport_discovery();
usb_init();
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 96%
rename from adb/jdwp_service.cpp
rename to adb/daemon/jdwp_service.cpp
index 5f070d9..3a3f399 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) {
@@ -457,7 +457,7 @@
delete s;
}
-static int jdwp_socket_enqueue(asocket* s, std::string) {
+static int jdwp_socket_enqueue(asocket* s, apacket::payload_type) {
/* you can't write to this asocket */
D("LS(%d): JDWP socket received data?", s->id);
s->peer->close(s->peer);
@@ -472,7 +472,7 @@
* on the second one, close the connection
*/
if (!jdwp->pass) {
- std::string data;
+ apacket::payload_type data;
data.resize(s->get_max_payload());
size_t len = jdwp_process_list(&data[0], data.size());
data.resize(len);
@@ -509,7 +509,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;
@@ -519,7 +519,8 @@
for (auto& t : _jdwp_trackers) {
if (t->peer) {
// The tracker might not have been connected yet.
- t->peer->enqueue(t->peer, data);
+ apacket::payload_type payload(data.begin(), data.end());
+ t->peer->enqueue(t->peer, std::move(payload));
}
}
}
@@ -545,7 +546,7 @@
JdwpTracker* t = (JdwpTracker*)s;
if (t->need_initial) {
- std::string data;
+ apacket::payload_type data;
data.resize(s->get_max_payload());
data.resize(jdwp_process_list_msg(&data[0], data.size()));
t->need_initial = false;
@@ -553,7 +554,7 @@
}
}
-static int jdwp_tracker_enqueue(asocket* s, std::string) {
+static int jdwp_tracker_enqueue(asocket* s, apacket::payload_type) {
/* you can't write to this socket */
D("LS(%d): JDWP tracker received data?", s->id);
s->peer->close(s->peer);
diff --git a/adb/daemon/main.cpp b/adb/daemon/main.cpp
index 5adeb44..232d9c5 100644
--- a/adb/daemon/main.cpp
+++ b/adb/daemon/main.cpp
@@ -20,6 +20,7 @@
#include <errno.h>
#include <getopt.h>
+#include <malloc.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
@@ -183,9 +184,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();
@@ -237,6 +239,9 @@
}
int main(int argc, char** argv) {
+ // Set M_DECAY_TIME so that our allocations aren't immediately purged on free.
+ mallopt(M_DECAY_TIME, 1);
+
while (true) {
static struct option opts[] = {
{"root_seclabel", required_argument, nullptr, 's'},
diff --git a/adb/remount_service.cpp b/adb/daemon/remount_service.cpp
similarity index 60%
rename from adb/remount_service.cpp
rename to adb/daemon/remount_service.cpp
index d679a6d..eb46903 100644
--- a/adb/remount_service.cpp
+++ b/adb/daemon/remount_service.cpp
@@ -21,18 +21,23 @@
#include <errno.h>
#include <fcntl.h>
#include <mntent.h>
+#include <spawn.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mount.h>
+#include <sys/vfs.h>
#include <unistd.h>
#include <string>
+#include <vector>
#include <android-base/properties.h>
+#include <ext4_utils/ext4_utils.h>
#include "adb.h"
#include "adb_io.h"
+#include "adb_unique_fd.h"
#include "adb_utils.h"
#include "fs_mgr.h"
@@ -82,7 +87,62 @@
return result;
}
-static bool remount_partition(int fd, const char* dir) {
+static bool fs_has_shared_blocks(const char* dev) {
+ struct statfs fs;
+ if (statfs(dev, &fs) == -1 || fs.f_type == EXT4_SUPER_MAGIC) {
+ return false;
+ }
+ unique_fd fd(unix_open(dev, O_RDONLY));
+ if (fd < 0) {
+ return false;
+ }
+ struct ext4_super_block sb;
+ if (lseek64(fd, 1024, SEEK_SET) < 0 || unix_read(fd, &sb, sizeof(sb)) < 0) {
+ return false;
+ }
+ struct fs_info info;
+ if (ext4_parse_sb(&sb, &info) < 0) {
+ return false;
+ }
+ return (info.feat_ro_compat & EXT4_FEATURE_RO_COMPAT_SHARED_BLOCKS) != 0;
+}
+
+static bool can_unshare_blocks(int fd, const char* dev) {
+ const char* E2FSCK_BIN = "/system/bin/e2fsck";
+ if (access(E2FSCK_BIN, X_OK)) {
+ WriteFdFmt(fd, "e2fsck is not available, cannot undo deduplication on %s\n", dev);
+ return false;
+ }
+
+ pid_t child;
+ char* env[] = {nullptr};
+ const char* argv[] = {E2FSCK_BIN, "-n", "-E", "unshare_blocks", dev, nullptr};
+ if (posix_spawn(&child, E2FSCK_BIN, nullptr, nullptr, const_cast<char**>(argv), env)) {
+ WriteFdFmt(fd, "failed to e2fsck to check deduplication: %s\n", strerror(errno));
+ return false;
+ }
+ int status = 0;
+ int ret = TEMP_FAILURE_RETRY(waitpid(child, &status, 0));
+ if (ret < 0) {
+ WriteFdFmt(fd, "failed to get e2fsck status: %s\n", strerror(errno));
+ return false;
+ }
+ if (!WIFEXITED(status)) {
+ WriteFdFmt(fd, "e2fsck exited abnormally with status %d\n", status);
+ return false;
+ }
+ int rc = WEXITSTATUS(status);
+ if (rc != 0) {
+ WriteFdFmt(fd,
+ "%s is deduplicated, and an e2fsck check failed. It might not "
+ "have enough free-space to be remounted as writable.\n",
+ dev);
+ return false;
+ }
+ return true;
+}
+
+static bool remount_partition(int fd, const char* dir, std::vector<std::string>& dedup) {
if (!directory_exists(dir)) {
return true;
}
@@ -108,6 +168,15 @@
return false;
}
if (mount(dev.c_str(), dir, "none", MS_REMOUNT, nullptr) == -1) {
+ if (errno == EROFS && fs_has_shared_blocks(dev.c_str())) {
+ if (!can_unshare_blocks(fd, dev.c_str())) {
+ return false;
+ }
+ // We return true so remount_service() can detect that the only
+ // failure was deduplicated filesystems.
+ dedup.push_back(dev);
+ return true;
+ }
WriteFdFmt(fd, "remount of the %s superblock failed: %s\n", dir, strerror(errno));
return false;
}
@@ -140,17 +209,29 @@
}
bool success = true;
+ std::vector<std::string> dedup;
if (android::base::GetBoolProperty("ro.build.system_root_image", false)) {
- success &= remount_partition(fd, "/");
+ success &= remount_partition(fd, "/", dedup);
} else {
- success &= remount_partition(fd, "/system");
+ success &= remount_partition(fd, "/system", dedup);
}
- success &= remount_partition(fd, "/odm");
- success &= remount_partition(fd, "/oem");
- success &= remount_partition(fd, "/product");
- success &= remount_partition(fd, "/vendor");
+ success &= remount_partition(fd, "/odm", dedup);
+ success &= remount_partition(fd, "/oem", dedup);
+ success &= remount_partition(fd, "/product", dedup);
+ success &= remount_partition(fd, "/vendor", dedup);
- WriteFdExactly(fd, success ? "remount succeeded\n" : "remount failed\n");
+ if (!success) {
+ WriteFdExactly(fd, "remount failed\n");
+ } else if (dedup.empty()) {
+ WriteFdExactly(fd, "remount succeeded\n");
+ } else {
+ WriteFdExactly(fd,
+ "The following partitions are deduplicated and could "
+ "not be remounted:\n");
+ for (const std::string& name : dedup) {
+ WriteFdFmt(fd, " %s\n", name.c_str());
+ }
+ }
adb_close(fd);
}
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 99%
rename from adb/shell_service.cpp
rename to adb/daemon/shell_service.cpp
index da1222b..401c99c 100644
--- a/adb/shell_service.cpp
+++ b/adb/daemon/shell_service.cpp
@@ -344,7 +344,8 @@
}
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..c724b11 100644
--- a/adb/daemon/usb.cpp
+++ b/adb/daemon/usb.cpp
@@ -234,6 +234,10 @@
for (unsigned i = 0; i < USB_FFS_NUM_BUFS; i++) {
aiob->iocbs[i] = &aiob->iocb[i];
}
+ memset(&aiob->ctx, 0, sizeof(aiob->ctx));
+ if (io_setup(USB_FFS_NUM_BUFS, &aiob->ctx)) {
+ D("[ aio: got error on io_setup (%d) ]", errno);
+ }
}
static int getMaxPacketSize(int ffs_fd) {
@@ -269,7 +273,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,23 +304,18 @@
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;
}
- 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);
- }
-
h->read_aiob.fd = h->bulk_out;
h->write_aiob.fd = h->bulk_in;
return true;
@@ -498,8 +497,6 @@
h->kicked = false;
adb_close(h->bulk_out);
adb_close(h->bulk_in);
- io_destroy(h->read_aiob.ctx);
- io_destroy(h->write_aiob.ctx);
// Notify usb_adb_open_thread to open a new connection.
h->lock.lock();
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/range.h b/adb/range.h
deleted file mode 100644
index 7a0b822..0000000
--- a/adb/range.h
+++ /dev/null
@@ -1,65 +0,0 @@
-#pragma once
-
-/*
- * 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 <string>
-
-#include <android-base/logging.h>
-
-struct Range {
- explicit Range(std::string data) : data_(std::move(data)) {}
-
- Range(const Range& copy) = delete;
- Range& operator=(const Range& copy) = delete;
-
- Range(Range&& move) = default;
- Range& operator=(Range&& move) = default;
-
- bool empty() const {
- return size() == 0;
- }
-
- size_t size() const {
- return data_.size() - begin_offset_ - end_offset_;
- };
-
- void drop_front(size_t n) {
- CHECK_GE(size(), n);
- begin_offset_ += n;
- }
-
- void drop_end(size_t n) {
- CHECK_GE(size(), n);
- end_offset_ += n;
- }
-
- char* data() {
- return &data_[0] + begin_offset_;
- }
-
- std::string::iterator begin() {
- return data_.begin() + begin_offset_;
- }
-
- std::string::iterator end() {
- return data_.end() - end_offset_;
- }
-
- std::string data_;
- size_t begin_offset_ = 0;
- size_t end_offset_ = 0;
-};
diff --git a/adb/socket.h b/adb/socket.h
index 88499b5..e0fd87f 100644
--- a/adb/socket.h
+++ b/adb/socket.h
@@ -24,9 +24,8 @@
#include <string>
#include "fdevent.h"
-#include "range.h"
+#include "types.h"
-struct apacket;
class atransport;
/* An asocket represents one half of a connection between a local and
@@ -73,7 +72,7 @@
* peer->ready() when we once again are ready to
* receive data.
*/
- int (*enqueue)(asocket* s, std::string data) = nullptr;
+ int (*enqueue)(asocket* s, apacket::payload_type data) = nullptr;
/* ready is called by the peer when it is ready for
* us to send data via enqueue again
diff --git a/adb/socket_test.cpp b/adb/socket_test.cpp
index 6b40056..04214a2 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) {
+ apacket::payload_type 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 04bd080..e567ff4 100644
--- a/adb/sockets.cpp
+++ b/adb/sockets.cpp
@@ -37,8 +37,8 @@
#include "adb.h"
#include "adb_io.h"
-#include "range.h"
#include "transport.h"
+#include "types.h"
static std::recursive_mutex& local_socket_list_lock = *new std::recursive_mutex();
static unsigned local_socket_next_id = 1;
@@ -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.
@@ -147,7 +147,7 @@
// Returns false if the socket has been closed and destroyed as a side-effect of this function.
static bool local_socket_flush_outgoing(asocket* s) {
const size_t max_payload = s->get_max_payload();
- std::string data;
+ apacket::payload_type data;
data.resize(max_payload);
char* x = &data[0];
size_t avail = max_payload;
@@ -214,7 +214,7 @@
return true;
}
-static int local_socket_enqueue(asocket* s, std::string data) {
+static int local_socket_enqueue(asocket* s, apacket::payload_type data) {
D("LS(%d): enqueue %zu", s->id, data.size());
Range r(std::move(data));
@@ -394,7 +394,7 @@
}
#endif /* ADB_HOST */
-static int remote_socket_enqueue(asocket* s, std::string data) {
+static int remote_socket_enqueue(asocket* s, apacket::payload_type data) {
D("entered remote_socket_enqueue RS(%d) WRITE fd=%d peer.fd=%d", s->id, s->fd, s->peer->fd);
apacket* p = get_apacket();
@@ -476,8 +476,7 @@
p->msg.arg0 = s->id;
// adbd expects a null-terminated string.
- p->payload = destination;
- p->payload.push_back('\0');
+ p->payload.assign(destination, destination + strlen(destination) + 1);
p->msg.data_length = p->payload.size();
if (p->msg.data_length > s->get_max_payload()) {
@@ -612,7 +611,7 @@
#endif // ADB_HOST
-static int smart_socket_enqueue(asocket* s, std::string data) {
+static int smart_socket_enqueue(asocket* s, apacket::payload_type data) {
#if ADB_HOST
char* service = nullptr;
char* serial = nullptr;
@@ -623,7 +622,8 @@
D("SS(%d): enqueue %zu", s->id, data.size());
if (s->smart_socket_data.empty()) {
- s->smart_socket_data = std::move(data);
+ // TODO: Make this a BlockChain?
+ s->smart_socket_data.assign(data.begin(), data.end());
} else {
std::copy(data.begin(), data.end(), std::back_inserter(s->smart_socket_data));
}
@@ -750,7 +750,7 @@
if (!s->transport) {
SendFail(s->peer->fd, "device offline (no transport)");
goto fail;
- } else if (s->transport->GetConnectionState() == kCsOffline) {
+ } else if (!ConnectionStateIsOnline(s->transport->GetConnectionState())) {
/* if there's no remote we fail the connection
** right here and terminate 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/uio.h b/adb/sysdeps/uio.h
new file mode 100644
index 0000000..d06ef89
--- /dev/null
+++ b/adb/sysdeps/uio.h
@@ -0,0 +1,39 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <sys/types.h>
+
+#if defined(_WIN32)
+
+// Layout of this struct must match struct WSABUF (verified via static assert in sysdeps_win32.cpp)
+struct adb_iovec {
+ size_t iov_len;
+ void* iov_base;
+};
+
+ssize_t adb_writev(int fd, const adb_iovec* iov, int iovcnt);
+
+#else
+
+#include <sys/uio.h>
+using adb_iovec = struct iovec;
+#define adb_writev writev
+
+#endif
+
+#pragma GCC poison writev
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..bfac342 100644
--- a/adb/sysdeps_win32.cpp
+++ b/adb/sysdeps_win32.cpp
@@ -36,6 +36,7 @@
#include <android-base/errors.h>
#include <android-base/logging.h>
+#include <android-base/macros.h>
#include <android-base/stringprintf.h>
#include <android-base/strings.h>
#include <android-base/utf8.h>
@@ -43,6 +44,8 @@
#include "adb.h"
#include "adb_utils.h"
+#include "sysdeps/uio.h"
+
extern void fatal(const char *fmt, ...);
/* forward declarations */
@@ -57,6 +60,7 @@
int (*_fh_lseek)(FH, int, int);
int (*_fh_read)(FH, void*, int);
int (*_fh_write)(FH, const void*, int);
+ int (*_fh_writev)(FH, const adb_iovec*, int);
} FHClassRec;
static void _fh_file_init(FH);
@@ -64,6 +68,7 @@
static int _fh_file_lseek(FH, int, int);
static int _fh_file_read(FH, void*, int);
static int _fh_file_write(FH, const void*, int);
+static int _fh_file_writev(FH, const adb_iovec*, int);
static const FHClassRec _fh_file_class = {
_fh_file_init,
@@ -71,6 +76,7 @@
_fh_file_lseek,
_fh_file_read,
_fh_file_write,
+ _fh_file_writev,
};
static void _fh_socket_init(FH);
@@ -78,6 +84,7 @@
static int _fh_socket_lseek(FH, int, int);
static int _fh_socket_read(FH, void*, int);
static int _fh_socket_write(FH, const void*, int);
+static int _fh_socket_writev(FH, const adb_iovec*, int);
static const FHClassRec _fh_socket_class = {
_fh_socket_init,
@@ -85,6 +92,7 @@
_fh_socket_lseek,
_fh_socket_read,
_fh_socket_write,
+ _fh_socket_writev,
};
#define assert(cond) \
@@ -248,57 +256,88 @@
/**************************************************************************/
/**************************************************************************/
-static void _fh_file_init( FH f ) {
+static void _fh_file_init(FH f) {
f->fh_handle = INVALID_HANDLE_VALUE;
}
-static int _fh_file_close( FH f ) {
- CloseHandle( f->fh_handle );
+static int _fh_file_close(FH f) {
+ CloseHandle(f->fh_handle);
f->fh_handle = INVALID_HANDLE_VALUE;
return 0;
}
-static int _fh_file_read( FH f, void* buf, int len ) {
- DWORD read_bytes;
+static int _fh_file_read(FH f, void* buf, int len) {
+ DWORD read_bytes;
- if ( !ReadFile( f->fh_handle, buf, (DWORD)len, &read_bytes, NULL ) ) {
- D( "adb_read: could not read %d bytes from %s", len, f->name );
+ if (!ReadFile(f->fh_handle, buf, (DWORD)len, &read_bytes, NULL)) {
+ D("adb_read: could not read %d bytes from %s", len, f->name);
errno = EIO;
return -1;
} else if (read_bytes < (DWORD)len) {
f->eof = 1;
}
- return (int)read_bytes;
+ return read_bytes;
}
-static int _fh_file_write( FH f, const void* buf, int len ) {
- DWORD wrote_bytes;
+static int _fh_file_write(FH f, const void* buf, int len) {
+ DWORD wrote_bytes;
- if ( !WriteFile( f->fh_handle, buf, (DWORD)len, &wrote_bytes, NULL ) ) {
- D( "adb_file_write: could not write %d bytes from %s", len, f->name );
+ if (!WriteFile(f->fh_handle, buf, (DWORD)len, &wrote_bytes, NULL)) {
+ D("adb_file_write: could not write %d bytes from %s", len, f->name);
errno = EIO;
return -1;
} else if (wrote_bytes < (DWORD)len) {
f->eof = 1;
}
- return (int)wrote_bytes;
+ return wrote_bytes;
}
-static int _fh_file_lseek( FH f, int pos, int origin ) {
- DWORD method;
- DWORD result;
+static int _fh_file_writev(FH f, const adb_iovec* iov, int iovcnt) {
+ if (iovcnt <= 0) {
+ errno = EINVAL;
+ return -1;
+ }
- switch (origin)
- {
- case SEEK_SET: method = FILE_BEGIN; break;
- case SEEK_CUR: method = FILE_CURRENT; break;
- case SEEK_END: method = FILE_END; break;
+ DWORD wrote_bytes = 0;
+
+ for (int i = 0; i < iovcnt; ++i) {
+ ssize_t rc = _fh_file_write(f, iov[i].iov_base, iov[i].iov_len);
+ if (rc == -1) {
+ return wrote_bytes > 0 ? wrote_bytes : -1;
+ } else if (rc == 0) {
+ return wrote_bytes;
+ }
+
+ wrote_bytes += rc;
+
+ if (static_cast<size_t>(rc) < iov[i].iov_len) {
+ return wrote_bytes;
+ }
+ }
+
+ return wrote_bytes;
+}
+
+static int _fh_file_lseek(FH f, int pos, int origin) {
+ DWORD method;
+ DWORD result;
+
+ switch (origin) {
+ case SEEK_SET:
+ method = FILE_BEGIN;
+ break;
+ case SEEK_CUR:
+ method = FILE_CURRENT;
+ break;
+ case SEEK_END:
+ method = FILE_END;
+ break;
default:
errno = EINVAL;
return -1;
}
- result = SetFilePointer( f->fh_handle, pos, NULL, method );
+ result = SetFilePointer(f->fh_handle, pos, NULL, method);
if (result == INVALID_SET_FILE_POINTER) {
errno = EIO;
return -1;
@@ -308,7 +347,6 @@
return (int)result;
}
-
/**************************************************************************/
/**************************************************************************/
/***** *****/
@@ -317,12 +355,11 @@
/**************************************************************************/
/**************************************************************************/
-int adb_open(const char* path, int options)
-{
- FH f;
+int adb_open(const char* path, int options) {
+ FH f;
- DWORD desiredAccess = 0;
- DWORD shareMode = FILE_SHARE_READ | FILE_SHARE_WRITE;
+ DWORD desiredAccess = 0;
+ DWORD shareMode = FILE_SHARE_READ | FILE_SHARE_WRITE;
switch (options) {
case O_RDONLY:
@@ -340,8 +377,8 @@
return -1;
}
- f = _fh_alloc( &_fh_file_class );
- if ( !f ) {
+ f = _fh_alloc(&_fh_file_class);
+ if (!f) {
return -1;
}
@@ -349,21 +386,21 @@
if (!android::base::UTF8ToWide(path, &path_wide)) {
return -1;
}
- f->fh_handle = CreateFileW( path_wide.c_str(), desiredAccess, shareMode,
- NULL, OPEN_EXISTING, 0, NULL );
+ f->fh_handle =
+ CreateFileW(path_wide.c_str(), desiredAccess, shareMode, NULL, OPEN_EXISTING, 0, NULL);
- if ( f->fh_handle == INVALID_HANDLE_VALUE ) {
+ if (f->fh_handle == INVALID_HANDLE_VALUE) {
const DWORD err = GetLastError();
_fh_close(f);
- D( "adb_open: could not open '%s': ", path );
+ D("adb_open: could not open '%s': ", path);
switch (err) {
case ERROR_FILE_NOT_FOUND:
- D( "file not found" );
+ D("file not found");
errno = ENOENT;
return -1;
case ERROR_PATH_NOT_FOUND:
- D( "path not found" );
+ D("path not found");
errno = ENOTDIR;
return -1;
@@ -374,18 +411,17 @@
}
}
- snprintf( f->name, sizeof(f->name), "%d(%s)", _fh_to_int(f), path );
- D( "adb_open: '%s' => fd %d", path, _fh_to_int(f) );
+ snprintf(f->name, sizeof(f->name), "%d(%s)", _fh_to_int(f), path);
+ D("adb_open: '%s' => fd %d", path, _fh_to_int(f));
return _fh_to_int(f);
}
/* ignore mode on Win32 */
-int adb_creat(const char* path, int mode)
-{
- FH f;
+int adb_creat(const char* path, int mode) {
+ FH f;
- f = _fh_alloc( &_fh_file_class );
- if ( !f ) {
+ f = _fh_alloc(&_fh_file_class);
+ if (!f) {
return -1;
}
@@ -393,23 +429,21 @@
if (!android::base::UTF8ToWide(path, &path_wide)) {
return -1;
}
- f->fh_handle = CreateFileW( path_wide.c_str(), GENERIC_WRITE,
- FILE_SHARE_READ | FILE_SHARE_WRITE,
- NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL,
- NULL );
+ f->fh_handle = CreateFileW(path_wide.c_str(), GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE,
+ NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
- if ( f->fh_handle == INVALID_HANDLE_VALUE ) {
+ if (f->fh_handle == INVALID_HANDLE_VALUE) {
const DWORD err = GetLastError();
_fh_close(f);
- D( "adb_creat: could not open '%s': ", path );
+ D("adb_creat: could not open '%s': ", path);
switch (err) {
case ERROR_FILE_NOT_FOUND:
- D( "file not found" );
+ D("file not found");
errno = ENOENT;
return -1;
case ERROR_PATH_NOT_FOUND:
- D( "path not found" );
+ D("path not found");
errno = ENOTDIR;
return -1;
@@ -419,57 +453,64 @@
return -1;
}
}
- snprintf( f->name, sizeof(f->name), "%d(%s)", _fh_to_int(f), path );
- D( "adb_creat: '%s' => fd %d", path, _fh_to_int(f) );
+ snprintf(f->name, sizeof(f->name), "%d(%s)", _fh_to_int(f), path);
+ D("adb_creat: '%s' => fd %d", path, _fh_to_int(f));
return _fh_to_int(f);
}
-
-int adb_read(int fd, void* buf, int len)
-{
- FH f = _fh_from_int(fd, __func__);
+int adb_read(int fd, void* buf, int len) {
+ FH f = _fh_from_int(fd, __func__);
if (f == NULL) {
+ errno = EBADF;
return -1;
}
- return f->clazz->_fh_read( f, buf, len );
+ return f->clazz->_fh_read(f, buf, len);
}
-
-int adb_write(int fd, const void* buf, int len)
-{
- FH f = _fh_from_int(fd, __func__);
+int adb_write(int fd, const void* buf, int len) {
+ FH f = _fh_from_int(fd, __func__);
if (f == NULL) {
+ errno = EBADF;
return -1;
}
return f->clazz->_fh_write(f, buf, len);
}
+ssize_t adb_writev(int fd, const adb_iovec* iov, int iovcnt) {
+ FH f = _fh_from_int(fd, __func__);
-int adb_lseek(int fd, int pos, int where)
-{
- FH f = _fh_from_int(fd, __func__);
+ if (f == NULL) {
+ errno = EBADF;
+ return -1;
+ }
+
+ return f->clazz->_fh_writev(f, iov, iovcnt);
+}
+
+int adb_lseek(int fd, int pos, int where) {
+ FH f = _fh_from_int(fd, __func__);
if (!f) {
+ errno = EBADF;
return -1;
}
return f->clazz->_fh_lseek(f, pos, where);
}
-
-int adb_close(int fd)
-{
- FH f = _fh_from_int(fd, __func__);
+int adb_close(int fd) {
+ FH f = _fh_from_int(fd, __func__);
if (!f) {
+ errno = EBADF;
return -1;
}
- D( "adb_close: %s", f->name);
+ D("adb_close: %s", f->name);
_fh_close(f);
return 0;
}
@@ -529,6 +570,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 +591,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 +607,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;
@@ -576,7 +623,7 @@
f->fh_socket = INVALID_SOCKET;
}
-static int _fh_socket_close( FH f ) {
+static int _fh_socket_close(FH f) {
if (f->fh_socket != INVALID_SOCKET) {
/* gently tell any peer that we're closing the socket */
if (shutdown(f->fh_socket, SD_BOTH) == SOCKET_ERROR) {
@@ -597,13 +644,13 @@
return 0;
}
-static int _fh_socket_lseek( FH f, int pos, int origin ) {
+static int _fh_socket_lseek(FH f, int pos, int origin) {
errno = EPIPE;
return -1;
}
static int _fh_socket_read(FH f, void* buf, int len) {
- int result = recv(f->fh_socket, reinterpret_cast<char*>(buf), len, 0);
+ int result = recv(f->fh_socket, reinterpret_cast<char*>(buf), len, 0);
if (result == SOCKET_ERROR) {
const DWORD err = WSAGetLastError();
// WSAEWOULDBLOCK is normal with a non-blocking socket, so don't trace
@@ -615,11 +662,11 @@
_socket_set_errno(err);
result = -1;
}
- return result;
+ return result;
}
static int _fh_socket_write(FH f, const void* buf, int len) {
- int result = send(f->fh_socket, reinterpret_cast<const char*>(buf), len, 0);
+ int result = send(f->fh_socket, reinterpret_cast<const char*>(buf), len, 0);
if (result == SOCKET_ERROR) {
const DWORD err = WSAGetLastError();
// WSAEWOULDBLOCK is normal with a non-blocking socket, so don't trace
@@ -633,13 +680,44 @@
} else {
// According to https://code.google.com/p/chromium/issues/detail?id=27870
// Winsock Layered Service Providers may cause this.
- CHECK_LE(result, len) << "Tried to write " << len << " bytes to "
- << f->name << ", but " << result
- << " bytes reportedly written";
+ CHECK_LE(result, len) << "Tried to write " << len << " bytes to " << f->name << ", but "
+ << result << " bytes reportedly written";
}
return result;
}
+// Make sure that adb_iovec is compatible with WSABUF.
+static_assert(sizeof(adb_iovec) == sizeof(WSABUF), "");
+static_assert(SIZEOF_MEMBER(adb_iovec, iov_len) == SIZEOF_MEMBER(WSABUF, len), "");
+static_assert(offsetof(adb_iovec, iov_len) == offsetof(WSABUF, len), "");
+
+static_assert(SIZEOF_MEMBER(adb_iovec, iov_base) == SIZEOF_MEMBER(WSABUF, buf), "");
+static_assert(offsetof(adb_iovec, iov_base) == offsetof(WSABUF, buf), "");
+
+static int _fh_socket_writev(FH f, const adb_iovec* iov, int iovcnt) {
+ if (iovcnt <= 0) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ WSABUF* wsabuf = reinterpret_cast<WSABUF*>(const_cast<adb_iovec*>(iov));
+ DWORD bytes_written = 0;
+ int result = WSASend(f->fh_socket, wsabuf, iovcnt, &bytes_written, 0, nullptr, nullptr);
+ if (result == SOCKET_ERROR) {
+ const DWORD err = WSAGetLastError();
+ // WSAEWOULDBLOCK is normal with a non-blocking socket, so don't trace
+ // that to reduce spam and confusion.
+ if (err != WSAEWOULDBLOCK) {
+ D("send fd %d failed: %s", _fh_to_int(f),
+ android::base::SystemErrorCodeToString(err).c_str());
+ }
+ _socket_set_errno(err);
+ result = -1;
+ }
+ CHECK_GE(static_cast<DWORD>(std::numeric_limits<int>::max()), bytes_written);
+ return static_cast<int>(bytes_written);
+}
+
/**************************************************************************/
/**************************************************************************/
/***** *****/
@@ -648,23 +726,15 @@
/**************************************************************************/
/**************************************************************************/
-#include <winsock2.h>
-
-static int _winsock_init;
-
-static void
-_init_winsock( void )
-{
- // TODO: Multiple threads calling this may potentially cause multiple calls
- // to WSAStartup() which offers no real benefit.
- if (!_winsock_init) {
- WSADATA wsaData;
- int rc = WSAStartup( MAKEWORD(2,2), &wsaData);
+static int _init_winsock(void) {
+ static std::once_flag once;
+ std::call_once(once, []() {
+ WSADATA wsaData;
+ int rc = WSAStartup(MAKEWORD(2, 2), &wsaData);
if (rc != 0) {
fatal("adb: could not initialize Winsock: %s",
android::base::SystemErrorCodeToString(rc).c_str());
}
- _winsock_init = 1;
// Note that we do not call atexit() to register WSACleanup to be called
// at normal process termination because:
@@ -679,9 +749,12 @@
// setupapi.dll which tries to load wintrust.dll which tries to load
// crypt32.dll which calls atexit() which tries to acquire the C
// Runtime lock that the other thread holds.
- }
+ });
+ return 0;
}
+static int _winsock_init = _init_winsock();
+
// Map a socket type to an explicit socket protocol instead of using the socket
// protocol of 0. Explicit socket protocols are used by most apps and we should
// do the same to reduce the chance of exercising uncommon code-paths that might
@@ -709,8 +782,6 @@
return -1;
}
- if (!_winsock_init) _init_winsock();
-
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_port = htons(port);
@@ -759,8 +830,6 @@
return -1;
}
- if (!_winsock_init) _init_winsock();
-
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_port = htons(port);
@@ -837,8 +906,6 @@
return -1;
}
- if (!_winsock_init) _init_winsock();
-
struct addrinfo hints;
memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_UNSPEC;
@@ -906,52 +973,49 @@
return fd;
}
-int adb_register_socket(SOCKET s) {
- FH f = _fh_alloc( &_fh_socket_class );
+int adb_register_socket(SOCKET s) {
+ FH f = _fh_alloc(&_fh_socket_class);
f->fh_socket = s;
return _fh_to_int(f);
}
#undef accept
-int adb_socket_accept(int serverfd, struct sockaddr* addr, socklen_t *addrlen)
-{
- FH serverfh = _fh_from_int(serverfd, __func__);
+int adb_socket_accept(int serverfd, struct sockaddr* addr, socklen_t* addrlen) {
+ FH serverfh = _fh_from_int(serverfd, __func__);
- if ( !serverfh || serverfh->clazz != &_fh_socket_class ) {
+ if (!serverfh || serverfh->clazz != &_fh_socket_class) {
D("adb_socket_accept: invalid fd %d", serverfd);
errno = EBADF;
return -1;
}
- unique_fh fh(_fh_alloc( &_fh_socket_class ));
+ unique_fh fh(_fh_alloc(&_fh_socket_class));
if (!fh) {
PLOG(ERROR) << "adb_socket_accept: failed to allocate accepted socket "
"descriptor";
return -1;
}
- fh->fh_socket = accept( serverfh->fh_socket, addr, addrlen );
+ fh->fh_socket = accept(serverfh->fh_socket, addr, addrlen);
if (fh->fh_socket == INVALID_SOCKET) {
const DWORD err = WSAGetLastError();
- LOG(ERROR) << "adb_socket_accept: accept on fd " << serverfd <<
- " failed: " + android::base::SystemErrorCodeToString(err);
- _socket_set_errno( err );
+ LOG(ERROR) << "adb_socket_accept: accept on fd " << serverfd
+ << " failed: " + android::base::SystemErrorCodeToString(err);
+ _socket_set_errno(err);
return -1;
}
const int fd = _fh_to_int(fh.get());
- snprintf( fh->name, sizeof(fh->name), "%d(accept:%s)", fd, serverfh->name );
- D( "adb_socket_accept on fd %d returns fd %d", serverfd, fd );
+ snprintf(fh->name, sizeof(fh->name), "%d(accept:%s)", fd, serverfh->name);
+ D("adb_socket_accept on fd %d returns fd %d", serverfd, fd);
fh.release();
- return fd;
+ return fd;
}
+int adb_setsockopt(int fd, int level, int optname, const void* optval, socklen_t optlen) {
+ FH fh = _fh_from_int(fd, __func__);
-int adb_setsockopt( int fd, int level, int optname, const void* optval, socklen_t optlen )
-{
- FH fh = _fh_from_int(fd, __func__);
-
- if ( !fh || fh->clazz != &_fh_socket_class ) {
+ if (!fh || fh->clazz != &_fh_socket_class) {
D("adb_setsockopt: invalid fd %d", fd);
errno = EBADF;
return -1;
@@ -961,13 +1025,13 @@
// to set SOL_SOCKET, SO_SNDBUF/SO_RCVBUF, ignore it since the OS has
// auto-tuning.
- int result = setsockopt( fh->fh_socket, level, optname,
- reinterpret_cast<const char*>(optval), optlen );
- if ( result == SOCKET_ERROR ) {
+ int result =
+ setsockopt(fh->fh_socket, level, optname, reinterpret_cast<const char*>(optval), optlen);
+ if (result == SOCKET_ERROR) {
const DWORD err = WSAGetLastError();
- D("adb_setsockopt: setsockopt on fd %d level %d optname %d failed: %s\n",
- fd, level, optname, android::base::SystemErrorCodeToString(err).c_str());
- _socket_set_errno( err );
+ D("adb_setsockopt: setsockopt on fd %d level %d optname %d failed: %s\n", fd, level,
+ optname, android::base::SystemErrorCodeToString(err).c_str());
+ _socket_set_errno(err);
result = -1;
}
return result;
diff --git a/adb/test_adb.py b/adb/test_adb.py
index e771106..ddd3ff0 100644
--- a/adb/test_adb.py
+++ b/adb/test_adb.py
@@ -21,9 +21,11 @@
"""
from __future__ import print_function
+import binascii
import contextlib
import os
import random
+import select
import socket
import struct
import subprocess
@@ -33,8 +35,117 @@
import adb
-class NonApiTest(unittest.TestCase):
- """Tests for ADB that aren't a part of the AndroidDevice API."""
+@contextlib.contextmanager
+def fake_adbd(protocol=socket.AF_INET, port=0):
+ """Creates a fake ADB daemon that just replies with a CNXN packet."""
+
+ serversock = socket.socket(protocol, socket.SOCK_STREAM)
+ serversock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
+ if protocol == socket.AF_INET:
+ serversock.bind(('127.0.0.1', port))
+ else:
+ serversock.bind(('::1', port))
+ serversock.listen(1)
+
+ # A pipe that is used to signal the thread that it should terminate.
+ readpipe, writepipe = os.pipe()
+
+ def _adb_packet(command, arg0, arg1, data):
+ bin_command = struct.unpack('I', command)[0]
+ buf = struct.pack('IIIIII', bin_command, arg0, arg1, len(data), 0,
+ bin_command ^ 0xffffffff)
+ buf += data
+ return buf
+
+ def _handle():
+ rlist = [readpipe, serversock]
+ cnxn_sent = {}
+ while True:
+ read_ready, _, _ = select.select(rlist, [], [])
+ for ready in read_ready:
+ if ready == readpipe:
+ # Closure pipe
+ os.close(ready)
+ serversock.shutdown(socket.SHUT_RDWR)
+ serversock.close()
+ return
+ elif ready == serversock:
+ # Server socket
+ conn, _ = ready.accept()
+ rlist.append(conn)
+ else:
+ # Client socket
+ data = ready.recv(1024)
+ if not data or data.startswith('OPEN'):
+ if ready in cnxn_sent:
+ del cnxn_sent[ready]
+ ready.shutdown(socket.SHUT_RDWR)
+ ready.close()
+ rlist.remove(ready)
+ continue
+ if ready in cnxn_sent:
+ continue
+ cnxn_sent[ready] = True
+ ready.sendall(_adb_packet('CNXN', 0x01000001, 1024 * 1024,
+ 'device::ro.product.name=fakeadb'))
+
+ port = serversock.getsockname()[1]
+ server_thread = threading.Thread(target=_handle)
+ server_thread.start()
+
+ try:
+ yield port
+ finally:
+ os.close(writepipe)
+ server_thread.join()
+
+
+@contextlib.contextmanager
+def adb_connect(unittest, serial):
+ """Context manager for an ADB connection.
+
+ This automatically disconnects when done with the connection.
+ """
+
+ output = subprocess.check_output(['adb', 'connect', serial])
+ unittest.assertEqual(output.strip(), 'connected to {}'.format(serial))
+
+ try:
+ yield
+ finally:
+ # Perform best-effort disconnection. Discard the output.
+ subprocess.Popen(['adb', 'disconnect', serial],
+ stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE).communicate()
+
+
+@contextlib.contextmanager
+def adb_server():
+ """Context manager for an ADB server.
+
+ This creates an ADB server and returns the port it's listening on.
+ """
+
+ port = 5038
+ # Kill any existing server on this non-default port.
+ subprocess.check_output(['adb', '-P', str(port), 'kill-server'],
+ stderr=subprocess.STDOUT)
+ read_pipe, write_pipe = os.pipe()
+ proc = subprocess.Popen(['adb', '-L', 'tcp:localhost:{}'.format(port),
+ 'fork-server', 'server',
+ '--reply-fd', str(write_pipe)])
+ try:
+ os.close(write_pipe)
+ greeting = os.read(read_pipe, 1024)
+ assert greeting == 'OK\n', repr(greeting)
+ yield port
+ finally:
+ proc.terminate()
+ proc.wait()
+
+
+class CommandlineTest(unittest.TestCase):
+ """Tests for the ADB commandline."""
def test_help(self):
"""Make sure we get _something_ out of help."""
@@ -56,28 +167,37 @@
revision_line, r'^Revision [0-9a-f]{12}-android$')
def test_tcpip_error_messages(self):
- p = subprocess.Popen(['adb', 'tcpip'], stdout=subprocess.PIPE,
- stderr=subprocess.STDOUT)
- out, _ = p.communicate()
- self.assertEqual(1, p.returncode)
+ """Make sure 'adb tcpip' parsing is sane."""
+ proc = subprocess.Popen(['adb', 'tcpip'], stdout=subprocess.PIPE,
+ stderr=subprocess.STDOUT)
+ out, _ = proc.communicate()
+ self.assertEqual(1, proc.returncode)
self.assertIn('requires an argument', out)
- p = subprocess.Popen(['adb', 'tcpip', 'foo'], stdout=subprocess.PIPE,
- stderr=subprocess.STDOUT)
- out, _ = p.communicate()
- self.assertEqual(1, p.returncode)
+ proc = subprocess.Popen(['adb', 'tcpip', 'foo'], stdout=subprocess.PIPE,
+ stderr=subprocess.STDOUT)
+ out, _ = proc.communicate()
+ self.assertEqual(1, proc.returncode)
self.assertIn('invalid port', out)
- # Helper method that reads a pipe until it is closed, then sets the event.
- def _read_pipe_and_set_event(self, pipe, event):
- x = pipe.read()
+
+class ServerTest(unittest.TestCase):
+ """Tests for the ADB server."""
+
+ @staticmethod
+ def _read_pipe_and_set_event(pipe, event):
+ """Reads a pipe until it is closed, then sets the event."""
+ pipe.read()
event.set()
- # Test that launch_server() does not let the adb server inherit
- # stdin/stdout/stderr handles which can cause callers of adb.exe to hang.
- # This test also runs fine on unix even though the impetus is an issue
- # unique to Windows.
def test_handle_inheritance(self):
+ """Test that launch_server() does not inherit handles.
+
+ launch_server() should not let the adb server inherit
+ stdin/stdout/stderr handles, which can cause callers of adb.exe to hang.
+ This test also runs fine on unix even though the impetus is an issue
+ unique to Windows.
+ """
# This test takes 5 seconds to run on Windows: if there is no adb server
# running on the the port used below, adb kill-server tries to make a
# TCP connection to a closed port and that takes 1 second on Windows;
@@ -99,29 +219,30 @@
try:
# Run the adb client and have it start the adb server.
- p = subprocess.Popen(['adb', '-P', str(port), 'start-server'],
- stdin=subprocess.PIPE, stdout=subprocess.PIPE,
- stderr=subprocess.PIPE)
+ proc = subprocess.Popen(['adb', '-P', str(port), 'start-server'],
+ stdin=subprocess.PIPE,
+ stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE)
# Start threads that set events when stdout/stderr are closed.
stdout_event = threading.Event()
stdout_thread = threading.Thread(
- target=self._read_pipe_and_set_event,
- args=(p.stdout, stdout_event))
+ target=ServerTest._read_pipe_and_set_event,
+ args=(proc.stdout, stdout_event))
stdout_thread.daemon = True
stdout_thread.start()
stderr_event = threading.Event()
stderr_thread = threading.Thread(
- target=self._read_pipe_and_set_event,
- args=(p.stderr, stderr_event))
+ target=ServerTest._read_pipe_and_set_event,
+ args=(proc.stderr, stderr_event))
stderr_thread.daemon = True
stderr_thread.start()
# Wait for the adb client to finish. Once that has occurred, if
# stdin/stderr/stdout are still open, it must be open in the adb
# server.
- p.wait()
+ proc.wait()
# Try to write to stdin which we expect is closed. If it isn't
# closed, we should get an IOError. If we don't get an IOError,
@@ -129,7 +250,7 @@
# probably letting the adb server inherit stdin which would be
# wrong.
with self.assertRaises(IOError):
- p.stdin.write('x')
+ proc.stdin.write('x')
# Wait a few seconds for stdout/stderr to be closed (in the success
# case, this won't wait at all). If there is a timeout, that means
@@ -143,8 +264,12 @@
subprocess.check_output(['adb', '-P', str(port), 'kill-server'],
stderr=subprocess.STDOUT)
- # Use SO_LINGER to cause TCP RST segment to be sent on socket close.
+
+class EmulatorTest(unittest.TestCase):
+ """Tests for the emulator connection."""
+
def _reset_socket_on_close(self, sock):
+ """Use SO_LINGER to cause TCP RST segment to be sent on socket close."""
# The linger structure is two shorts on Windows, but two ints on Unix.
linger_format = 'hh' if os.name == 'nt' else 'ii'
l_onoff = 1
@@ -162,19 +287,18 @@
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:
+ 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.
- p = subprocess.Popen(
+ proc = subprocess.Popen(
['adb', '-s', 'emulator-' + str(port), 'emu', 'kill'],
stderr=subprocess.STDOUT)
@@ -183,12 +307,16 @@
# If WSAECONNABORTED (10053) is raised by any socket calls,
# then adb probably isn't reading the data that we sent it.
conn.sendall('Android Console: type \'help\' for a list ' +
- 'of commands\r\n')
+ 'of commands\r\n')
conn.sendall('OK\r\n')
- with contextlib.closing(conn.makefile()) as f:
- self.assertEqual('kill\n', f.readline())
- self.assertEqual('quit\n', f.readline())
+ with contextlib.closing(conn.makefile()) as connf:
+ line = connf.readline()
+ if line.startswith('auth'):
+ # Ignore the first auth line.
+ line = connf.readline()
+ self.assertEqual('kill\n', line)
+ self.assertEqual('quit\n', connf.readline())
conn.sendall('OK: killing emulator, bye bye\r\n')
@@ -201,46 +329,117 @@
self._reset_socket_on_close(conn)
# Wait for adb to finish, so we can check return code.
- p.communicate()
+ proc.communicate()
# If this fails, adb probably isn't ignoring WSAECONNRESET when
# reading the response from the adb emu kill command (on Windows).
- self.assertEqual(0, p.returncode)
+ self.assertEqual(0, proc.returncode)
+
+ def test_emulator_connect(self):
+ """Ensure that the emulator can connect.
+
+ Bug: http://b/78991667
+ """
+ with adb_server() as server_port:
+ with fake_adbd() as port:
+ serial = 'emulator-{}'.format(port - 1)
+ # Ensure that the emulator is not there.
+ try:
+ subprocess.check_output(['adb', '-P', str(server_port),
+ '-s', serial, 'get-state'],
+ stderr=subprocess.STDOUT)
+ self.fail('Device should not be available')
+ except subprocess.CalledProcessError as err:
+ self.assertEqual(
+ err.output.strip(),
+ 'error: device \'{}\' not found'.format(serial))
+
+ # Let the ADB server know that the emulator has started.
+ with contextlib.closing(
+ socket.socket(socket.AF_INET, socket.SOCK_STREAM)) as sock:
+ sock.connect(('localhost', server_port))
+ command = 'host:emulator:{}'.format(port)
+ sock.sendall('%04x%s' % (len(command), command))
+
+ # Ensure the emulator is there.
+ subprocess.check_call(['adb', '-P', str(server_port),
+ '-s', serial, 'wait-for-device'])
+ output = subprocess.check_output(['adb', '-P', str(server_port),
+ '-s', serial, 'get-state'])
+ self.assertEqual(output.strip(), 'device')
+
+
+class ConnectionTest(unittest.TestCase):
+ """Tests for adb connect."""
def test_connect_ipv4_ipv6(self):
"""Ensure that `adb connect localhost:1234` will try both IPv4 and IPv6.
Bug: http://b/30313466
"""
- ipv4 = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
- ipv4.bind(('127.0.0.1', 0))
- ipv4.listen(1)
+ for protocol in (socket.AF_INET, socket.AF_INET6):
+ try:
+ with fake_adbd(protocol=protocol) as port:
+ serial = 'localhost:{}'.format(port)
+ with adb_connect(self, serial):
+ pass
+ except socket.error:
+ print("IPv6 not available, skipping")
+ continue
- ipv6 = socket.socket(socket.AF_INET6, socket.SOCK_STREAM)
- try:
- ipv6.bind(('::1', ipv4.getsockname()[1] + 1))
- ipv6.listen(1)
- except socket.error:
- print("IPv6 not available, skipping")
- return
+ def test_already_connected(self):
+ """Ensure that an already-connected device stays connected."""
- for s in (ipv4, ipv6):
- port = s.getsockname()[1]
- output = subprocess.check_output(
- ['adb', 'connect', 'localhost:{}'.format(port)])
+ with fake_adbd() as port:
+ serial = 'localhost:{}'.format(port)
+ with adb_connect(self, serial):
+ # b/31250450: this always returns 0 but probably shouldn't.
+ output = subprocess.check_output(['adb', 'connect', serial])
+ self.assertEqual(
+ output.strip(), 'already connected to {}'.format(serial))
- self.assertEqual(
- output.strip(), 'connected to localhost:{}'.format(port))
- s.close()
+ def test_reconnect(self):
+ """Ensure that a disconnected device reconnects."""
+
+ with fake_adbd() as port:
+ serial = 'localhost:{}'.format(port)
+ with adb_connect(self, serial):
+ output = subprocess.check_output(['adb', '-s', serial,
+ 'get-state'])
+ self.assertEqual(output.strip(), 'device')
+
+ # This will fail.
+ proc = subprocess.Popen(['adb', '-s', serial, 'shell', 'true'],
+ stdout=subprocess.PIPE,
+ stderr=subprocess.STDOUT)
+ output, _ = proc.communicate()
+ self.assertEqual(output.strip(), 'error: closed')
+
+ subprocess.check_call(['adb', '-s', serial, 'wait-for-device'])
+
+ output = subprocess.check_output(['adb', '-s', serial,
+ 'get-state'])
+ self.assertEqual(output.strip(), 'device')
+
+ # Once we explicitly kick a device, it won't attempt to
+ # reconnect.
+ output = subprocess.check_output(['adb', 'disconnect', serial])
+ self.assertEqual(
+ output.strip(), 'disconnected {}'.format(serial))
+ try:
+ subprocess.check_output(['adb', '-s', serial, 'get-state'],
+ stderr=subprocess.STDOUT)
+ self.fail('Device should not be available')
+ except subprocess.CalledProcessError as err:
+ self.assertEqual(
+ err.output.strip(),
+ 'error: device \'{}\' not found'.format(serial))
def main():
+ """Main entrypoint."""
random.seed(0)
- if len(adb.get_devices()) > 0:
- suite = unittest.TestLoader().loadTestsFromName(__name__)
- unittest.TextTestRunner(verbosity=3).run(suite)
- else:
- print('Test suite must be run with attached devices')
+ unittest.main(verbosity=3)
if __name__ == '__main__':
diff --git a/adb/test_device.py b/adb/test_device.py
index 72e1c67..f995be2 100644
--- a/adb/test_device.py
+++ b/adb/test_device.py
@@ -188,8 +188,6 @@
finally:
self.device.reverse_remove_all()
- # Note: If you run this test when adb connect'd to a physical device over
- # TCP, it will fail in adb reverse due to https://code.google.com/p/android/issues/detail?id=189821
def test_forward_reverse_echo(self):
"""Send data through adb forward and read it back via adb reverse"""
forward_port = 12345
@@ -1187,7 +1185,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..beec13a 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,8 +30,10 @@
#include <unistd.h>
#include <algorithm>
+#include <deque>
#include <list>
#include <mutex>
+#include <queue>
#include <thread>
#include <android-base/logging.h>
@@ -38,15 +42,18 @@
#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);
+static void register_transport(atransport* transport);
+static void remove_transport(atransport* transport);
+static void transport_unref(atransport* transport);
// TODO: unordered_map<TransportId, atransport*>
static auto& transport_list = *new std::list<atransport*>();
@@ -60,11 +67,254 @@
const char* const kFeatureLibusb = "libusb";
const char* const kFeaturePushSync = "push_sync";
+namespace {
+
+// A class that helps the Clang Thread Safety Analysis deal with
+// std::unique_lock. Given that std::unique_lock is movable, and the analysis
+// can not currently perform alias analysis, it is not annotated. In order to
+// assert that the mutex is held, a ScopedAssumeLocked can be created just after
+// the std::unique_lock.
+class SCOPED_CAPABILITY ScopedAssumeLocked {
+ public:
+ ScopedAssumeLocked(std::mutex& mutex) ACQUIRE(mutex) {}
+ ~ScopedAssumeLocked() RELEASE() {}
+};
+
+// Tracks and handles atransport*s that are attempting reconnection.
+class ReconnectHandler {
+ public:
+ ReconnectHandler() = default;
+ ~ReconnectHandler() = default;
+
+ // Starts the ReconnectHandler thread.
+ void Start();
+
+ // Requests the ReconnectHandler thread to stop.
+ void Stop();
+
+ // Adds the atransport* to the queue of reconnect attempts.
+ void TrackTransport(atransport* transport);
+
+ private:
+ // The main thread loop.
+ void Run();
+
+ // Tracks a reconnection attempt.
+ struct ReconnectAttempt {
+ atransport* transport;
+ std::chrono::system_clock::time_point deadline;
+ size_t attempts_left;
+ };
+
+ // Only retry for up to one minute.
+ static constexpr const std::chrono::seconds kDefaultTimeout = std::chrono::seconds(10);
+ static constexpr const size_t kMaxAttempts = 6;
+
+ // Protects all members.
+ std::mutex reconnect_mutex_;
+ bool running_ GUARDED_BY(reconnect_mutex_) = true;
+ std::thread handler_thread_;
+ std::condition_variable reconnect_cv_;
+ std::queue<ReconnectAttempt> reconnect_queue_ GUARDED_BY(reconnect_mutex_);
+
+ DISALLOW_COPY_AND_ASSIGN(ReconnectHandler);
+};
+
+void ReconnectHandler::Start() {
+ check_main_thread();
+ handler_thread_ = std::thread(&ReconnectHandler::Run, this);
+}
+
+void ReconnectHandler::Stop() {
+ check_main_thread();
+ {
+ std::lock_guard<std::mutex> lock(reconnect_mutex_);
+ running_ = false;
+ }
+ reconnect_cv_.notify_one();
+ handler_thread_.join();
+
+ // Drain the queue to free all resources.
+ std::lock_guard<std::mutex> lock(reconnect_mutex_);
+ while (!reconnect_queue_.empty()) {
+ ReconnectAttempt attempt = reconnect_queue_.front();
+ reconnect_queue_.pop();
+ remove_transport(attempt.transport);
+ }
+}
+
+void ReconnectHandler::TrackTransport(atransport* transport) {
+ check_main_thread();
+ {
+ std::lock_guard<std::mutex> lock(reconnect_mutex_);
+ if (!running_) return;
+ reconnect_queue_.emplace(ReconnectAttempt{
+ transport, std::chrono::system_clock::now() + ReconnectHandler::kDefaultTimeout,
+ ReconnectHandler::kMaxAttempts});
+ }
+ reconnect_cv_.notify_one();
+}
+
+void ReconnectHandler::Run() {
+ while (true) {
+ ReconnectAttempt attempt;
+ {
+ std::unique_lock<std::mutex> lock(reconnect_mutex_);
+ ScopedAssumeLocked assume_lock(reconnect_mutex_);
+
+ auto deadline = std::chrono::time_point<std::chrono::system_clock>::max();
+ if (!reconnect_queue_.empty()) deadline = reconnect_queue_.front().deadline;
+ reconnect_cv_.wait_until(lock, deadline, [&]() REQUIRES(reconnect_mutex_) {
+ return !running_ ||
+ (!reconnect_queue_.empty() && reconnect_queue_.front().deadline < deadline);
+ });
+
+ if (!running_) return;
+ attempt = reconnect_queue_.front();
+ reconnect_queue_.pop();
+ if (attempt.transport->kicked()) {
+ D("transport %s was kicked. giving up on it.", attempt.transport->serial);
+ remove_transport(attempt.transport);
+ continue;
+ }
+ }
+ D("attempting to reconnect %s", attempt.transport->serial);
+
+ if (!attempt.transport->Reconnect()) {
+ D("attempting to reconnect %s failed.", attempt.transport->serial);
+ if (attempt.attempts_left == 0) {
+ D("transport %s exceeded the number of retry attempts. giving up on it.",
+ attempt.transport->serial);
+ remove_transport(attempt.transport);
+ continue;
+ }
+
+ std::lock_guard<std::mutex> lock(reconnect_mutex_);
+ reconnect_queue_.emplace(ReconnectAttempt{
+ attempt.transport,
+ std::chrono::system_clock::now() + ReconnectHandler::kDefaultTimeout,
+ attempt.attempts_left - 1});
+ continue;
+ }
+
+ D("reconnection to %s succeeded.", attempt.transport->serial);
+ register_transport(attempt.transport);
+ }
+}
+
+static auto& reconnect_handler = *new ReconnectHandler();
+
+} // namespace
+
TransportId NextTransportId() {
static std::atomic<TransportId> next(1);
return next++;
}
+BlockingConnectionAdapter::BlockingConnectionAdapter(std::unique_ptr<BlockingConnection> connection)
+ : underlying_(std::move(connection)) {}
+
+BlockingConnectionAdapter::~BlockingConnectionAdapter() {
+ LOG(INFO) << "BlockingConnectionAdapter(" << this->transport_name_ << "): destructing";
+ Stop();
+}
+
+void BlockingConnectionAdapter::Start() {
+ 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_);
+ ScopedAssumeLocked assume_locked(mutex_);
+ cv_.wait(lock, [this]() REQUIRES(mutex_) {
+ return this->stopped_ || !this->write_queue_.empty();
+ });
+
+ if (this->stopped_) {
+ return;
+ }
+
+ std::unique_ptr<apacket> packet = std::move(this->write_queue_.front());
+ this->write_queue_.pop_front();
+ lock.unlock();
+
+ if (!this->underlying_->Write(packet.get())) {
+ break;
+ }
+ }
+ std::call_once(this->error_flag_, [this]() { this->error_callback_(this, "write failed"); });
+ });
+
+ 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 +393,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 +402,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,
@@ -429,7 +474,7 @@
delete tracker;
}
-static int device_tracker_enqueue(asocket* socket, std::string) {
+static int device_tracker_enqueue(asocket* socket, apacket::payload_type) {
/* you can't read from a device tracker, close immediately */
device_tracker_close(socket);
return -1;
@@ -438,7 +483,7 @@
static int device_tracker_send(device_tracker* tracker, const std::string& string) {
asocket* peer = tracker->socket.peer;
- std::string data;
+ apacket::payload_type data;
data.resize(4 + string.size());
char buf[5];
snprintf(buf, sizeof(buf), "%04x", static_cast<int>(string.size()));
@@ -559,9 +604,8 @@
return 0;
}
-static void transport_registration_func(int _fd, unsigned ev, void* data) {
+static void transport_registration_func(int _fd, unsigned ev, void*) {
tmsg m;
- int s[2];
atransport* t;
if (!(ev & FDE_READ)) {
@@ -575,13 +619,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);
@@ -602,35 +640,53 @@
/* don't create transport threads for inaccessible devices */
if (t->GetConnectionState() != kCsNoPerm) {
- /* initial references are the two threads */
- t->ref_count = 2;
+ // The connection gets a reference to the atransport. It will release it
+ // upon a read/write error.
+ t->ref_count++;
+ 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
}
{
std::lock_guard<std::recursive_mutex> lock(transport_lock);
- pending_list.remove(t);
- transport_list.push_front(t);
+ auto it = std::find(pending_list.begin(), pending_list.end(), t);
+ if (it != pending_list.end()) {
+ pending_list.remove(t);
+ transport_list.push_front(t);
+ }
}
update_transports();
}
+void init_reconnect_handler(void) {
+ reconnect_handler.Start();
+}
+
void init_transport_registration(void) {
int s[2];
@@ -649,6 +705,7 @@
}
void kick_all_transports() {
+ reconnect_handler.Stop();
// To avoid only writing part of a packet to a transport after exit, kick all transports.
std::lock_guard<std::recursive_mutex> lock(transport_lock);
for (auto t : transport_list) {
@@ -678,15 +735,21 @@
}
static void transport_unref(atransport* t) {
+ check_main_thread();
CHECK(t != nullptr);
std::lock_guard<std::recursive_mutex> lock(transport_lock);
CHECK_GT(t->ref_count, 0u);
t->ref_count--;
if (t->ref_count == 0) {
- D("transport: %s unref (kicking and closing)", t->serial);
- t->connection->Close();
- remove_transport(t);
+ t->connection()->Stop();
+ if (t->IsTcpDevice() && !t->kicked()) {
+ D("transport: %s unref (attempting reconnection) %d", t->serial, t->kicked());
+ reconnect_handler.TrackTransport(t);
+ } else {
+ D("transport: %s unref (kicking and closing)", t->serial);
+ remove_transport(t);
+ }
} else {
D("transport: %s unref (count=%zu)", t->serial, t->ref_count);
}
@@ -736,9 +799,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;
}
@@ -787,22 +848,41 @@
}
lock.unlock();
- // Don't return unauthorized devices; the caller can't do anything with them.
- if (result && result->GetConnectionState() == kCsUnauthorized && !accept_any_state) {
- *error_out = "device unauthorized.\n";
- char* ADB_VENDOR_KEYS = getenv("ADB_VENDOR_KEYS");
- *error_out += "This adb server's $ADB_VENDOR_KEYS is ";
- *error_out += ADB_VENDOR_KEYS ? ADB_VENDOR_KEYS : "not set";
- *error_out += "\n";
- *error_out += "Try 'adb kill-server' if that seems wrong.\n";
- *error_out += "Otherwise check for a confirmation dialog on your device.";
- result = nullptr;
- }
+ if (result && !accept_any_state) {
+ // The caller requires an active transport.
+ // Make sure that we're actually connected.
+ ConnectionState state = result->GetConnectionState();
+ switch (state) {
+ case kCsConnecting:
+ *error_out = "device still connecting";
+ result = nullptr;
+ break;
- // Don't return offline devices; the caller can't do anything with them.
- if (result && result->GetConnectionState() == kCsOffline && !accept_any_state) {
- *error_out = "device offline";
- result = nullptr;
+ case kCsAuthorizing:
+ *error_out = "device still authorizing";
+ result = nullptr;
+ break;
+
+ case kCsUnauthorized: {
+ *error_out = "device unauthorized.\n";
+ char* ADB_VENDOR_KEYS = getenv("ADB_VENDOR_KEYS");
+ *error_out += "This adb server's $ADB_VENDOR_KEYS is ";
+ *error_out += ADB_VENDOR_KEYS ? ADB_VENDOR_KEYS : "not set";
+ *error_out += "\n";
+ *error_out += "Try 'adb kill-server' if that seems wrong.\n";
+ *error_out += "Otherwise check for a confirmation dialog on your device.";
+ result = nullptr;
+ break;
+ }
+
+ case kCsOffline:
+ *error_out = "device offline";
+ result = nullptr;
+ break;
+
+ default:
+ break;
+ }
}
if (result) {
@@ -812,15 +892,38 @@
return result;
}
+bool ConnectionWaitable::WaitForConnection(std::chrono::milliseconds timeout) {
+ std::unique_lock<std::mutex> lock(mutex_);
+ ScopedAssumeLocked assume_locked(mutex_);
+ return cv_.wait_for(lock, timeout, [&]() REQUIRES(mutex_) {
+ return connection_established_ready_;
+ }) && connection_established_;
+}
+
+void ConnectionWaitable::SetConnectionEstablished(bool success) {
+ {
+ std::lock_guard<std::mutex> lock(mutex_);
+ if (connection_established_ready_) return;
+ connection_established_ready_ = true;
+ connection_established_ = success;
+ D("connection established with %d", success);
+ }
+ cv_.notify_one();
+}
+
+atransport::~atransport() {
+ // If the connection callback had not been run before, run it now.
+ SetConnectionEstablished(false);
+}
+
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();
+ if (!kicked_.exchange(true)) {
+ D("kicking transport %p %s", this, this->serial);
+ this->connection()->Stop();
}
}
@@ -833,7 +936,12 @@
connection_state_ = state;
}
-const std::string atransport::connection_state_name() const {
+void atransport::SetConnection(std::unique_ptr<Connection> connection) {
+ std::lock_guard<std::mutex> lock(mutex_);
+ connection_ = std::shared_ptr<Connection>(std::move(connection));
+}
+
+std::string atransport::connection_state_name() const {
ConnectionState state = GetConnectionState();
switch (state) {
case kCsOffline:
@@ -852,6 +960,10 @@
return "sideload";
case kCsUnauthorized:
return "unauthorized";
+ case kCsAuthorizing:
+ return "authorizing";
+ case kCsConnecting:
+ return "connecting";
default:
return "unknown";
}
@@ -964,6 +1076,14 @@
qual_match(target.c_str(), "device:", device, false);
}
+void atransport::SetConnectionEstablished(bool success) {
+ connection_waitable_->SetConnectionEstablished(success);
+}
+
+bool atransport::Reconnect() {
+ return reconnect_(this);
+}
+
#if ADB_HOST
// We use newline as our delimiter, make sure to never output it.
@@ -1044,8 +1164,9 @@
}
#endif // ADB_HOST
-int register_socket_transport(int s, const char* serial, int port, int local) {
- atransport* t = new atransport();
+int register_socket_transport(int s, const char* serial, int port, int local,
+ atransport::ReconnectCallback reconnect) {
+ atransport* t = new atransport(std::move(reconnect), kCsOffline);
if (!serial) {
char buf[32];
@@ -1065,7 +1186,7 @@
VLOG(TRANSPORT) << "socket transport " << transport->serial
<< " is already in pending_list and fails to register";
delete t;
- return -1;
+ return -EALREADY;
}
}
@@ -1074,7 +1195,7 @@
VLOG(TRANSPORT) << "socket transport " << transport->serial
<< " is already in transport_list and fails to register";
delete t;
- return -1;
+ return -EALREADY;
}
}
@@ -1083,8 +1204,15 @@
lock.unlock();
+ auto waitable = t->connection_waitable();
register_transport(t);
- return 0;
+
+ if (local == 1) {
+ // Do not wait for emulator transports.
+ return 0;
+ }
+
+ return waitable->WaitForConnection(std::chrono::seconds(10)) ? 0 : -1;
}
#if ADB_HOST
@@ -1119,7 +1247,7 @@
void register_usb_transport(usb_handle* usb, const char* serial, const char* devpath,
unsigned writeable) {
- atransport* t = new atransport((writeable ? kCsOffline : kCsNoPerm));
+ atransport* t = new atransport(writeable ? kCsOffline : kCsNoPerm);
D("transport: %p init'ing for usb_handle %p (sn='%s')", t, usb, serial ? serial : "");
init_usb_transport(t, usb);
@@ -1143,8 +1271,9 @@
void unregister_usb_transport(usb_handle* usb) {
std::lock_guard<std::recursive_mutex> lock(transport_lock);
transport_list.remove_if([usb](atransport* t) {
- if (auto connection = dynamic_cast<UsbConnection*>(t->connection.get())) {
- return connection->handle_ == usb && t->GetConnectionState() == kCsNoPerm;
+ auto connection = t->connection();
+ if (auto usb_connection = dynamic_cast<UsbConnection*>(connection.get())) {
+ return usb_connection->handle_ == usb && t->GetConnectionState() == kCsNoPerm;
}
return false;
});
diff --git a/adb/transport.h b/adb/transport.h
index 9700f44..ae9cc02 100644
--- a/adb/transport.h
+++ b/adb/transport.h
@@ -20,14 +20,19 @@
#include <sys/types.h>
#include <atomic>
+#include <chrono>
+#include <condition_variable>
#include <deque>
#include <functional>
#include <list>
#include <memory>
#include <mutex>
#include <string>
+#include <thread>
#include <unordered_set>
+#include <android-base/macros.h>
+#include <android-base/thread_annotations.h>
#include <openssl/rsa.h>
#include "adb.h"
@@ -57,15 +62,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 +114,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 +150,7 @@
unique_fd fd_;
};
-struct UsbConnection : public Connection {
+struct UsbConnection : public BlockingConnection {
explicit UsbConnection(usb_handle* handle) : handle_(handle) {}
~UsbConnection();
@@ -101,6 +162,35 @@
usb_handle* handle_;
};
+// Waits for a transport's connection to be not pending. This is a separate
+// object so that the transport can be destroyed and another thread can be
+// notified of it in a race-free way.
+class ConnectionWaitable {
+ public:
+ ConnectionWaitable() = default;
+ ~ConnectionWaitable() = default;
+
+ // Waits until the first CNXN packet has been received by the owning
+ // atransport, or the specified timeout has elapsed. Can be called from any
+ // thread.
+ //
+ // Returns true if the CNXN packet was received in a timely fashion, false
+ // otherwise.
+ bool WaitForConnection(std::chrono::milliseconds timeout);
+
+ // Can be called from any thread when the connection stops being pending.
+ // Only the first invocation will be acknowledged, the rest will be no-ops.
+ void SetConnectionEstablished(bool success);
+
+ private:
+ bool connection_established_ GUARDED_BY(mutex_) = false;
+ bool connection_established_ready_ GUARDED_BY(mutex_) = false;
+ std::mutex mutex_;
+ std::condition_variable cv_;
+
+ DISALLOW_COPY_AND_ASSIGN(ConnectionWaitable);
+};
+
class atransport {
public:
// TODO(danalbert): We expose waaaaaaay too much stuff because this was
@@ -108,34 +198,43 @@
// class in one go is a very large change. Given how bad our testing is,
// it's better to do this piece by piece.
- atransport(ConnectionState state = kCsOffline)
- : id(NextTransportId()), connection_state_(state) {
- transport_fde = {};
+ using ReconnectCallback = std::function<bool(atransport*)>;
+
+ atransport(ReconnectCallback reconnect, ConnectionState state)
+ : id(NextTransportId()),
+ kicked_(false),
+ connection_state_(state),
+ connection_waitable_(std::make_shared<ConnectionWaitable>()),
+ connection_(nullptr),
+ reconnect_(std::move(reconnect)) {
// Initialize protocol to min version for compatibility with older versions.
// Version will be updated post-connect.
protocol_version = A_VERSION_MIN;
max_payload = MAX_PAYLOAD;
}
- virtual ~atransport() {}
+ atransport(ConnectionState state = kCsOffline)
+ : atransport([](atransport*) { return false; }, state) {}
+ virtual ~atransport();
int Write(apacket* p);
void Kick();
+ bool kicked() const { return kicked_; }
// ConnectionState can be read by all threads, but can only be written in the main thread.
ConnectionState GetConnectionState() const;
void SetConnectionState(ConnectionState state);
+ void SetConnection(std::unique_ptr<Connection> connection);
+ std::shared_ptr<Connection> connection() {
+ std::lock_guard<std::mutex> lock(mutex_);
+ return connection_;
+ }
+
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;
- std::unique_ptr<Connection> connection;
-
// Used to identify transports for clients.
char* serial = nullptr;
char* product = nullptr;
@@ -152,8 +251,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;
@@ -187,8 +286,19 @@
// This is to make it easier to use the same network target for both fastboot and adb.
bool MatchesTarget(const std::string& target) const;
-private:
- bool kicked_ = false;
+ // Notifies that the atransport is no longer waiting for the connection
+ // being established.
+ void SetConnectionEstablished(bool success);
+
+ // Gets a shared reference to the ConnectionWaitable.
+ std::shared_ptr<ConnectionWaitable> connection_waitable() { return connection_waitable_; }
+
+ // Attempts to reconnect with the underlying Connection. Returns true if the
+ // reconnection attempt succeeded.
+ bool Reconnect();
+
+ private:
+ std::atomic<bool> kicked_;
// A set of features transmitted in the banner with the initial connection.
// This is stored in the banner as 'features=feature0,feature1,etc'.
@@ -204,6 +314,18 @@
std::deque<std::shared_ptr<RSA>> keys_;
#endif
+ // A sharable object that can be used to wait for the atransport's
+ // connection to be established.
+ std::shared_ptr<ConnectionWaitable> connection_waitable_;
+
+ // The underlying connection object.
+ std::shared_ptr<Connection> connection_ GUARDED_BY(mutex_);
+
+ // A callback that will be invoked when the atransport needs to reconnect.
+ ReconnectCallback reconnect_;
+
+ std::mutex mutex_;
+
DISALLOW_COPY_AND_ASSIGN(atransport);
};
@@ -225,6 +347,7 @@
// Stops iteration and returns false if fn returns false, otherwise returns true.
bool iterate_transports(std::function<bool(const atransport*)> fn);
+void init_reconnect_handler(void);
void init_transport_registration(void);
void init_mdns_transport_discovery(void);
std::string list_transports(bool long_listing);
@@ -239,7 +362,8 @@
void connect_device(const std::string& address, std::string* response);
/* cause new transports to be init'd and added to the list */
-int register_socket_transport(int s, const char* serial, int port, int local);
+int register_socket_transport(int s, const char* serial, int port, int local,
+ atransport::ReconnectCallback reconnect);
// This should only be used for transports with connection_state == kCsNoPerm.
void unregister_usb_transport(usb_handle* usb);
diff --git a/adb/transport_benchmark.cpp b/adb/transport_benchmark.cpp
new file mode 100644
index 0000000..da24aa7
--- /dev/null
+++ b/adb/transport_benchmark.cpp
@@ -0,0 +1,183 @@
+/*
+ * 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 <malloc.h>
+#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) {
+ // Set M_DECAY_TIME so that our allocations aren't immediately purged on free.
+ mallopt(M_DECAY_TIME, 1);
+
+ 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..181d666 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
@@ -67,28 +68,24 @@
return local_connect_arbitrary_ports(port - 1, port, &dummy) == 0;
}
-void connect_device(const std::string& address, std::string* response) {
- if (address.empty()) {
- *response = "empty address";
- return;
- }
-
+std::tuple<unique_fd, int, std::string> tcp_connect(const std::string& address,
+ std::string* response) {
std::string serial;
std::string host;
int port = DEFAULT_ADB_LOCAL_TRANSPORT_PORT;
if (!android::base::ParseNetAddress(address, &host, &port, &serial, response)) {
- return;
+ return std::make_tuple(unique_fd(), port, serial);
}
std::string error;
- int fd = network_connect(host.c_str(), port, SOCK_STREAM, 10, &error);
+ unique_fd fd(network_connect(host.c_str(), port, SOCK_STREAM, 10, &error));
if (fd == -1) {
*response = android::base::StringPrintf("unable to connect to %s: %s",
serial.c_str(), error.c_str());
- return;
+ return std::make_tuple(std::move(fd), port, serial);
}
- D("client: connected %s remote on fd %d", serial.c_str(), fd);
+ D("client: connected %s remote on fd %d", serial.c_str(), fd.get());
close_on_exec(fd);
disable_tcp_nagle(fd);
@@ -97,10 +94,45 @@
D("warning: failed to configure TCP keepalives (%s)", strerror(errno));
}
- int ret = register_socket_transport(fd, serial.c_str(), port, 0);
+ return std::make_tuple(std::move(fd), port, serial);
+}
+
+void connect_device(const std::string& address, std::string* response) {
+ if (address.empty()) {
+ *response = "empty address";
+ return;
+ }
+
+ unique_fd fd;
+ int port;
+ std::string serial;
+ std::tie(fd, port, serial) = tcp_connect(address, response);
+ auto reconnect = [address](atransport* t) {
+ std::string response;
+ unique_fd fd;
+ int port;
+ std::string serial;
+ std::tie(fd, port, serial) = tcp_connect(address, &response);
+ if (fd == -1) {
+ D("reconnect failed: %s", response.c_str());
+ return false;
+ }
+
+ // This invokes the part of register_socket_transport() that needs to be
+ // invoked if the atransport* has already been setup. This eventually
+ // calls atransport->SetConnection() with a newly created Connection*
+ // that will in turn send the CNXN packet.
+ return init_socket_transport(t, fd.release(), port, 0) >= 0;
+ };
+
+ int ret = register_socket_transport(fd.release(), serial.c_str(), port, 0, std::move(reconnect));
if (ret < 0) {
adb_close(fd);
- *response = android::base::StringPrintf("already connected to %s", serial.c_str());
+ if (ret == -EALREADY) {
+ *response = android::base::StringPrintf("already connected to %s", serial.c_str());
+ } else {
+ *response = android::base::StringPrintf("failed to connect to %s", serial.c_str());
+ }
} else {
*response = android::base::StringPrintf("connected to %s", serial.c_str());
}
@@ -130,7 +162,8 @@
close_on_exec(fd);
disable_tcp_nagle(fd);
std::string serial = getEmulatorSerialString(console_port);
- if (register_socket_transport(fd, serial.c_str(), adb_port, 1) == 0) {
+ if (register_socket_transport(fd, serial.c_str(), adb_port, 1,
+ [](atransport*) { return false; }) == 0) {
return 0;
}
adb_close(fd);
@@ -234,7 +267,8 @@
close_on_exec(fd);
disable_tcp_nagle(fd);
std::string serial = android::base::StringPrintf("host-%d", fd);
- if (register_socket_transport(fd, serial.c_str(), port, 1) != 0) {
+ if (register_socket_transport(fd, serial.c_str(), port, 1,
+ [](atransport*) { return false; }) != 0) {
adb_close(fd);
}
}
@@ -333,7 +367,8 @@
/* Host is connected. Register the transport, and start the
* exchange. */
std::string serial = android::base::StringPrintf("host-%d", fd);
- if (register_socket_transport(fd, serial.c_str(), port, 1) != 0 ||
+ if (register_socket_transport(fd, serial.c_str(), port, 1,
+ [](atransport*) { return false; }) != 0 ||
!WriteFdExactly(fd, _start_req, strlen(_start_req))) {
adb_close(fd);
}
@@ -445,13 +480,14 @@
int fail = 0;
unique_fd fd(s);
- t->sync_token = 1;
t->type = kTransportLocal;
#if ADB_HOST
// Emulator connection.
if (local) {
- t->connection.reset(new EmulatorConnection(std::move(fd), adb_port));
+ auto emulator_connection = std::make_unique<EmulatorConnection>(std::move(fd), adb_port);
+ t->SetConnection(
+ 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 +506,7 @@
#endif
// Regular tcp connection.
- t->connection.reset(new FdConnection(std::move(fd)));
+ auto fd_connection = std::make_unique<FdConnection>(std::move(fd));
+ t->SetConnection(std::make_unique<BlockingConnectionAdapter>(std::move(fd_connection)));
return fail;
}
diff --git a/adb/transport_usb.cpp b/adb/transport_usb.cpp
index d7565f6..94b2e37 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->SetConnection(std::make_unique<BlockingConnectionAdapter>(std::move(connection)));
t->type = kTransportUsb;
}
diff --git a/adb/types.h b/adb/types.h
new file mode 100644
index 0000000..dd3e063
--- /dev/null
+++ b/adb/types.h
@@ -0,0 +1,163 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <algorithm>
+#include <utility>
+
+#include <android-base/logging.h>
+
+#include "sysdeps/memory.h"
+
+// Essentially std::vector<char>, except without zero initialization or reallocation.
+struct Block {
+ using iterator = char*;
+
+ Block() {}
+
+ explicit Block(size_t size) { allocate(size); }
+
+ template <typename Iterator>
+ Block(Iterator begin, Iterator end) : Block(end - begin) {
+ std::copy(begin, end, data_);
+ }
+
+ Block(const Block& copy) = delete;
+ Block(Block&& move) {
+ std::swap(data_, move.data_);
+ std::swap(capacity_, move.capacity_);
+ std::swap(size_, move.size_);
+ }
+
+ Block& operator=(const Block& copy) = delete;
+ Block& operator=(Block&& move) {
+ clear();
+
+ std::swap(data_, move.data_);
+ std::swap(capacity_, move.capacity_);
+ std::swap(size_, move.size_);
+
+ return *this;
+ }
+
+ ~Block() { clear(); }
+
+ void resize(size_t new_size) {
+ if (!data_) {
+ allocate(new_size);
+ } else {
+ CHECK_GE(capacity_, new_size);
+ size_ = new_size;
+ }
+ }
+
+ template <typename InputIt>
+ void assign(InputIt begin, InputIt end) {
+ clear();
+ allocate(end - begin);
+ std::copy(begin, end, data_);
+ }
+
+ void clear() {
+ free(data_);
+ capacity_ = 0;
+ size_ = 0;
+ }
+
+ size_t capacity() const { return capacity_; }
+ size_t size() const { return size_; }
+ bool empty() const { return size() == 0; }
+
+ char* data() { return data_; }
+ const char* data() const { return data_; }
+
+ char* begin() { return data_; }
+ const char* begin() const { return data_; }
+
+ char* end() { return data() + size_; }
+ const char* end() const { return data() + size_; }
+
+ char& operator[](size_t idx) { return data()[idx]; }
+ const char& operator[](size_t idx) const { return data()[idx]; }
+
+ bool operator==(const Block& rhs) const {
+ return size() == rhs.size() && memcmp(data(), rhs.data(), size()) == 0;
+ }
+
+ private:
+ void allocate(size_t size) {
+ CHECK(data_ == nullptr);
+ CHECK_EQ(0ULL, capacity_);
+ CHECK_EQ(0ULL, size_);
+ if (size != 0) {
+ data_ = static_cast<char*>(malloc(size));
+ capacity_ = size;
+ size_ = size;
+ }
+ }
+
+ char* data_ = nullptr;
+ size_t capacity_ = 0;
+ size_t size_ = 0;
+};
+
+struct amessage {
+ uint32_t command; /* command identifier constant */
+ uint32_t arg0; /* first argument */
+ uint32_t arg1; /* second argument */
+ uint32_t data_length; /* length of payload (0 is allowed) */
+ uint32_t data_check; /* checksum of data payload */
+ uint32_t magic; /* command ^ 0xffffffff */
+};
+
+struct apacket {
+ using payload_type = Block;
+ amessage msg;
+ payload_type payload;
+};
+
+struct Range {
+ explicit Range(apacket::payload_type data) : data_(std::move(data)) {}
+
+ Range(const Range& copy) = delete;
+ Range& operator=(const Range& copy) = delete;
+
+ Range(Range&& move) = default;
+ Range& operator=(Range&& move) = default;
+
+ size_t size() const { return data_.size() - begin_offset_ - end_offset_; };
+ bool empty() const { return size() == 0; }
+
+ void drop_front(size_t n) {
+ CHECK_GE(size(), n);
+ begin_offset_ += n;
+ }
+
+ void drop_end(size_t n) {
+ CHECK_GE(size(), n);
+ end_offset_ += n;
+ }
+
+ char* data() { return &data_[0] + begin_offset_; }
+
+ apacket::payload_type::iterator begin() { return data_.begin() + begin_offset_; }
+ apacket::payload_type::iterator end() { return data_.end() - end_offset_; }
+
+ apacket::payload_type data_;
+ size_t begin_offset_ = 0;
+ size_t end_offset_ = 0;
+};
diff --git a/base/Android.bp b/base/Android.bp
index 5d70d47..ec81f61 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",
],
@@ -123,6 +124,7 @@
"errors_test.cpp",
"file_test.cpp",
"logging_test.cpp",
+ "macros_test.cpp",
"parsedouble_test.cpp",
"parseint_test.cpp",
"parsenetaddress_test.cpp",
@@ -160,4 +162,5 @@
suffix: "64",
},
},
+ test_suites: ["device-tests"],
}
diff --git a/base/include/android-base/macros.h b/base/include/android-base/macros.h
index 25f2ff4..fd6efb2 100644
--- a/base/include/android-base/macros.h
+++ b/base/include/android-base/macros.h
@@ -20,6 +20,8 @@
#include <stddef.h> // for size_t
#include <unistd.h> // for TEMP_FAILURE_RETRY
+#include <utility>
+
// bionic and glibc both have TEMP_FAILURE_RETRY, but eg Mac OS' libc doesn't.
#ifndef TEMP_FAILURE_RETRY
#define TEMP_FAILURE_RETRY(exp) \
@@ -114,6 +116,8 @@
((sizeof(a) / sizeof(*(a))) / \
static_cast<size_t>(!(sizeof(a) % sizeof(*(a)))))
+#define SIZEOF_MEMBER(t, f) sizeof(std::declval<t>().f)
+
// Changing this definition will cause you a lot of pain. A majority of
// vendor code defines LIKELY and UNLIKELY this way, and includes
// this header through an indirect path.
diff --git a/base/include/android-base/parseint.h b/base/include/android-base/parseint.h
index 2c8570e..1b7cc5f 100644
--- a/base/include/android-base/parseint.h
+++ b/base/include/android-base/parseint.h
@@ -19,6 +19,7 @@
#include <errno.h>
#include <stdlib.h>
+#include <string.h>
#include <limits>
#include <string>
@@ -31,14 +32,20 @@
// otherwise valid values will be rejected. Returns boolean success; 'out'
// is untouched if parsing fails.
template <typename T>
-bool ParseUint(const char* s, T* out,
- T max = std::numeric_limits<T>::max()) {
+bool ParseUint(const char* s, T* out, T max = std::numeric_limits<T>::max(),
+ bool allow_suffixes = false) {
int base = (s[0] == '0' && (s[1] == 'x' || s[1] == 'X')) ? 16 : 10;
errno = 0;
char* end;
unsigned long long int result = strtoull(s, &end, base);
- if (errno != 0 || s == end || *end != '\0') {
- return false;
+ if (errno != 0 || end == s) return false;
+ if (*end != '\0') {
+ const char* suffixes = "bkmgtpe";
+ const char* suffix;
+ if (!allow_suffixes || (suffix = strchr(suffixes, tolower(*end))) == nullptr) return false;
+#if __clang__ // TODO: win32 still builds with GCC :-(
+ if (__builtin_mul_overflow(result, 1ULL << (10 * (suffix - suffixes)), &result)) return false;
+#endif
}
if (max < result) {
return false;
@@ -49,9 +56,20 @@
// TODO: string_view
template <typename T>
-bool ParseUint(const std::string& s, T* out,
- T max = std::numeric_limits<T>::max()) {
- return ParseUint(s.c_str(), out, max);
+bool ParseUint(const std::string& s, T* out, T max = std::numeric_limits<T>::max(),
+ bool allow_suffixes = false) {
+ return ParseUint(s.c_str(), out, max, allow_suffixes);
+}
+
+template <typename T>
+bool ParseByteCount(const char* s, T* out, T max = std::numeric_limits<T>::max()) {
+ return ParseUint(s, out, max, true);
+}
+
+// TODO: string_view
+template <typename T>
+bool ParseByteCount(const std::string& s, T* out, T max = std::numeric_limits<T>::max()) {
+ return ParseByteCount(s.c_str(), out, max);
}
// Parses the signed decimal integer in the string 's' and sets 'out' to
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..a33da22 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>
@@ -53,42 +54,9 @@
#endif
#include <android-base/macros.h>
+#include <android-base/parseint.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__)
@@ -115,6 +83,23 @@
return progname;
}
#endif
+
+#if defined(__linux__)
+int OpenKmsg() {
+#if defined(__ANDROID__)
+ // pick up 'file w /dev/kmsg' environment from daemon's init rc file
+ const auto val = getenv("ANDROID_FILE__dev_kmsg");
+ if (val != nullptr) {
+ int fd;
+ if (android::base::ParseInt(val, &fd, 0)) {
+ auto flags = fcntl(fd, F_GETFL);
+ if ((flags != -1) && ((flags & O_ACCMODE) == O_WRONLY)) return fd;
+ }
+ }
+#endif
+ return TEMP_FAILURE_RETRY(open("/dev/kmsg", O_WRONLY | O_CLOEXEC));
+}
+#endif
} // namespace
namespace android {
@@ -183,7 +168,7 @@
static_assert(arraysize(kLogSeverityToKernelLogLevel) == android::base::FATAL + 1,
"Mismatch in size of kLogSeverityToKernelLogLevel and values in LogSeverity");
- static int klog_fd = TEMP_FAILURE_RETRY(open("/dev/kmsg", O_WRONLY | O_CLOEXEC));
+ static int klog_fd = OpenKmsg();
if (klog_fd == -1) return;
int level = kLogSeverityToKernelLogLevel[severity];
@@ -223,8 +208,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/adb/transport_mdns_unsupported.cpp b/base/macros_test.cpp
similarity index 64%
copy from adb/transport_mdns_unsupported.cpp
copy to base/macros_test.cpp
index 387d341..2b522db 100644
--- a/adb/transport_mdns_unsupported.cpp
+++ b/base/macros_test.cpp
@@ -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,17 @@
* limitations under the License.
*/
-/* For when mDNS discovery is unsupported */
-void init_mdns_transport_discovery(void) {}
+#include "android-base/macros.h"
+
+#include <stdint.h>
+
+#include <gtest/gtest.h>
+
+TEST(macros, SIZEOF_MEMBER_macro) {
+ struct S {
+ int32_t i32;
+ double d;
+ };
+ ASSERT_EQ(4U, SIZEOF_MEMBER(S, i32));
+ ASSERT_EQ(8U, SIZEOF_MEMBER(S, d));
+}
diff --git a/base/parseint_test.cpp b/base/parseint_test.cpp
index 483b1d3..fb1c339 100644
--- a/base/parseint_test.cpp
+++ b/base/parseint_test.cpp
@@ -96,3 +96,44 @@
ASSERT_FALSE(android::base::ParseInt("456x", &u));
ASSERT_EQ(123u, u);
}
+
+TEST(parseint, ParseByteCount) {
+ uint64_t i = 0;
+ ASSERT_TRUE(android::base::ParseByteCount("123b", &i));
+ ASSERT_EQ(123ULL, i);
+
+ ASSERT_TRUE(android::base::ParseByteCount("8k", &i));
+ ASSERT_EQ(8ULL * 1024, i);
+
+ ASSERT_TRUE(android::base::ParseByteCount("8M", &i));
+ ASSERT_EQ(8ULL * 1024 * 1024, i);
+
+ ASSERT_TRUE(android::base::ParseByteCount("6g", &i));
+ ASSERT_EQ(6ULL * 1024 * 1024 * 1024, i);
+
+ ASSERT_TRUE(android::base::ParseByteCount("1T", &i));
+ ASSERT_EQ(1ULL * 1024 * 1024 * 1024 * 1024, i);
+
+ ASSERT_TRUE(android::base::ParseByteCount("2p", &i));
+ ASSERT_EQ(2ULL * 1024 * 1024 * 1024 * 1024 * 1024, i);
+
+ ASSERT_TRUE(android::base::ParseByteCount("4e", &i));
+ ASSERT_EQ(4ULL * 1024 * 1024 * 1024 * 1024 * 1024 * 1024, i);
+}
+
+TEST(parseint, ParseByteCount_invalid_suffix) {
+ unsigned u;
+ ASSERT_FALSE(android::base::ParseByteCount("1x", &u));
+}
+
+TEST(parseint, ParseByteCount_overflow) {
+ uint64_t u64;
+ ASSERT_FALSE(android::base::ParseByteCount("4294967295E", &u64));
+
+ uint16_t u16;
+ ASSERT_TRUE(android::base::ParseByteCount("63k", &u16));
+ ASSERT_EQ(63U * 1024, u16);
+ ASSERT_TRUE(android::base::ParseByteCount("65535b", &u16));
+ ASSERT_EQ(65535U, u16);
+ ASSERT_FALSE(android::base::ParseByteCount("65k", &u16));
+}
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..01b8948 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...
@@ -298,6 +312,7 @@
init : processing action (ro.boot.bootreason=*) from (/system/etc/init/bootstat.rc
init : processing action (sys.boot_completed=1 && sys.logbootcomplete=1) from (/system/etc/init/bootstat.rc
(/system/bin/bootstat --record_boot_complete --record_boot_reason --record_time_since_factory_reset -l)'
+ (/system/bin/bootstat --set_system_boot_reason --record_boot_complete --record_boot_reason --record_time_since_factory_reset -l)'
(/system/bin/bootstat -r post_decrypt_time_elapsed)'
init : Command 'exec - system log -- /system/bin/bootstat --record_boot_complete' action=sys.boot_completed=1 && sys.logbootcomplete=1 (/system/etc/init/bootstat.rc:
init : Command 'exec - system log -- /system/bin/bootstat --record_boot_reason' action=sys.boot_completed=1 && sys.logbootcomplete=1 (/system/etc/init/bootstat.rc:
@@ -407,29 +422,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}
}
@@ -566,9 +583,9 @@
duration_test
case ${TEST} in
bootloader | recovery | cold | hard | warm ) reason=${TEST} ;;
- *) reason=reboot,${TEST} ;;
+ *) reason=reboot,${TEST#optional_} ;;
esac
- adb reboot ${TEST}
+ adb reboot ${TEST#optional_}
wait_for_screen
bootloader_reason=`validate_property ro.boot.bootreason`
EXPECT_PROPERTY ro.boot.bootreason ${bootloader_reason}
@@ -792,6 +809,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
@@ -875,6 +949,20 @@
report_bootstat_logs reboot,adb
}
+[ "USAGE: test_rescueparty
+
+rescueparty test
+- adb reboot rescueparty
+- (wait until screen is up, boot has completed)
+- adb shell getprop sys.boot.reason
+- adb shell getprop ro.boot.bootreason
+- NB: should report reboot,rescueparty" ]
+test_optional_rescueparty() {
+ blind_reboot_test
+ echo "WARNING: legacy devices are allowed to fail following ro.boot.bootreason result" >&2
+ EXPECT_PROPERTY ro.boot.bootreason reboot,rescueparty
+}
+
[ "USAGE: test_Its_Just_So_Hard_reboot
Its Just So Hard reboot test:
@@ -1051,12 +1139,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 7a67894..39912f0 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>
@@ -140,7 +142,7 @@
// values.
const std::map<std::string, int32_t> kBootReasonMap = {
{"empty", kEmptyBootReason},
- {"unknown", kUnknownBootReason},
+ {"__BOOTSTAT_UNKNOWN__", kUnknownBootReason},
{"normal", 2},
{"recovery", 3},
{"reboot", 4},
@@ -193,12 +195,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},
@@ -229,7 +233,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},
+ {"reboot,rescueparty", 90},
{"charge", 91},
{"oem_tz_crash", 92},
{"uvlo", 93},
@@ -287,6 +291,22 @@
{"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},
+ {"kernel_panic,sysrq,livelock,alarm", 161}, // llkd
+ {"kernel_panic,sysrq,livelock,driver", 162}, // llkd
+ {"kernel_panic,sysrq,livelock,zombie", 163}, // llkd
};
// Converts a string value representing the reason the system booted to an
@@ -463,11 +483,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);
@@ -485,20 +507,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;
@@ -508,32 +725,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
@@ -568,26 +765,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;
}
}
@@ -626,28 +833,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.
@@ -685,7 +871,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/debuggerd/Android.bp b/debuggerd/Android.bp
index 7e6f24d..7c28b28 100644
--- a/debuggerd/Android.bp
+++ b/debuggerd/Android.bp
@@ -112,7 +112,6 @@
"libbase",
"libdebuggerd",
"libbacktrace",
- "libunwind",
"libunwindstack",
"libdexfile",
"liblzma",
@@ -158,7 +157,6 @@
static_libs: [
"libbacktrace",
- "libunwind",
"libunwindstack",
"liblzma",
"libbase",
@@ -221,6 +219,8 @@
stem: "debuggerd_test64",
},
},
+
+ test_suites: ["device-tests"],
}
cc_benchmark {
diff --git a/debuggerd/debuggerd_test.cpp b/debuggerd/debuggerd_test.cpp
index 397ff2f..dfb7a6a 100644
--- a/debuggerd/debuggerd_test.cpp
+++ b/debuggerd/debuggerd_test.cpp
@@ -80,8 +80,13 @@
return value; \
}()
+// Backtrace frame dump could contain:
+// #01 pc 0001cded /data/tmp/debuggerd_test32 (raise_debugger_signal+80)
+// or
+// #01 pc 00022a09 /data/tmp/debuggerd_test32 (offset 0x12000) (raise_debugger_signal+80)
#define ASSERT_BACKTRACE_FRAME(result, frame_name) \
- ASSERT_MATCH(result, R"(#\d\d pc [0-9a-f]+\s+ \S+ \()" frame_name R"(\+)");
+ ASSERT_MATCH(result, \
+ R"(#\d\d pc [0-9a-f]+\s+ \S+ (\(offset 0x[0-9a-f]+\) )?\()" frame_name R"(\+)");
static void tombstoned_intercept(pid_t target_pid, unique_fd* intercept_fd, unique_fd* output_fd,
InterceptStatus* status, DebuggerdDumpType intercept_type) {
@@ -346,7 +351,9 @@
std::string result;
ConsumeFd(std::move(output_fd), &result);
- ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\), code 0 \(SI_USER\), fault addr --------)");
+ ASSERT_MATCH(
+ result,
+ R"(signal 11 \(SIGSEGV\), code 0 \(SI_USER from pid \d+, uid \d+\), fault addr --------)");
ASSERT_MATCH(result, R"(backtrace:)");
}
@@ -354,7 +361,14 @@
int intercept_result;
unique_fd output_fd;
StartProcess([]() {
- android_set_abort_message("abort message goes here");
+ // Arrived at experimentally;
+ // logd truncates at 4062.
+ // strlen("Abort message: ''") is 17.
+ // That's 4045, but we also want a NUL.
+ char buf[4045 + 1];
+ memset(buf, 'x', sizeof(buf));
+ buf[sizeof(buf) - 1] = '\0';
+ android_set_abort_message(buf);
abort();
});
StartIntercept(&output_fd);
@@ -366,7 +380,7 @@
std::string result;
ConsumeFd(std::move(output_fd), &result);
- ASSERT_MATCH(result, R"(Abort message: 'abort message goes here')");
+ ASSERT_MATCH(result, R"(Abort message: 'x{4045}')");
}
TEST_F(CrasherTest, abort_message_backtrace) {
diff --git a/debuggerd/handler/debuggerd_fallback.cpp b/debuggerd/handler/debuggerd_fallback.cpp
index dea2e17..079a574 100644
--- a/debuggerd/handler/debuggerd_fallback.cpp
+++ b/debuggerd/handler/debuggerd_fallback.cpp
@@ -304,7 +304,16 @@
crash_mutex.lock();
if (lock_count++ > 0) {
- async_safe_format_log(ANDROID_LOG_ERROR, "libc", "recursed signal handler call, exiting");
+ async_safe_format_log(ANDROID_LOG_ERROR, "libc", "recursed signal handler call, aborting");
+ signal(SIGABRT, SIG_DFL);
+ raise(SIGABRT);
+ sigset_t sigset;
+ sigemptyset(&sigset);
+ sigaddset(&sigset, SIGABRT);
+ sigprocmask(SIG_UNBLOCK, &sigset, nullptr);
+
+ // Just in case...
+ async_safe_format_log(ANDROID_LOG_ERROR, "libc", "abort didn't exit, exiting");
_exit(1);
}
diff --git a/debuggerd/handler/debuggerd_handler.cpp b/debuggerd/handler/debuggerd_handler.cpp
index 05e6efa..c07a34a 100644
--- a/debuggerd/handler/debuggerd_handler.cpp
+++ b/debuggerd/handler/debuggerd_handler.cpp
@@ -169,24 +169,26 @@
return;
}
- const char* signal_name = get_signame(info->si_signo);
- bool has_address = signal_has_si_addr(info->si_signo, info->si_code);
-
- // Many signals don't have an address.
+ // Many signals don't have an address or sender.
char addr_desc[32] = ""; // ", fault addr 0x1234"
- if (has_address) {
+ if (signal_has_si_addr(info)) {
async_safe_format_buffer(addr_desc, sizeof(addr_desc), ", fault addr %p", info->si_addr);
}
+ pid_t self_pid = __getpid();
+ char sender_desc[32] = {}; // " from pid 1234, uid 666"
+ if (signal_has_sender(info, self_pid)) {
+ get_signal_sender(sender_desc, sizeof(sender_desc), info);
+ }
char main_thread_name[MAX_TASK_NAME_LEN + 1];
if (!get_main_thread_name(main_thread_name, sizeof(main_thread_name))) {
strncpy(main_thread_name, "<unknown>", sizeof(main_thread_name));
}
- async_safe_format_log(
- ANDROID_LOG_FATAL, "libc", "Fatal signal %d (%s), code %d (%s)%s in tid %d (%s), pid %d (%s)",
- info->si_signo, signal_name, info->si_code, get_sigcode(info->si_signo, info->si_code),
- addr_desc, __gettid(), thread_name, __getpid(), main_thread_name);
+ async_safe_format_log(ANDROID_LOG_FATAL, "libc",
+ "Fatal signal %d (%s), code %d (%s%s)%s in tid %d (%s), pid %d (%s)",
+ info->si_signo, get_signame(info), info->si_code, get_sigcode(info),
+ sender_desc, addr_desc, __gettid(), thread_name, self_pid, main_thread_name);
}
/*
diff --git a/debuggerd/libdebuggerd/include/libdebuggerd/utility.h b/debuggerd/libdebuggerd/include/libdebuggerd/utility.h
index 7b04e71..7c5304e 100644
--- a/debuggerd/libdebuggerd/include/libdebuggerd/utility.h
+++ b/debuggerd/libdebuggerd/include/libdebuggerd/utility.h
@@ -74,8 +74,10 @@
void drop_capabilities();
-bool signal_has_si_addr(int si_signo, int si_code);
-const char* get_signame(int sig);
-const char* get_sigcode(int signo, int code);
+bool signal_has_sender(const siginfo_t*, pid_t caller_pid);
+bool signal_has_si_addr(const siginfo_t*);
+void get_signal_sender(char* buf, size_t n, const siginfo_t*);
+const char* get_signame(const siginfo_t*);
+const char* get_sigcode(const siginfo_t*);
#endif // _DEBUGGERD_UTILITY_H
diff --git a/debuggerd/libdebuggerd/tombstone.cpp b/debuggerd/libdebuggerd/tombstone.cpp
index 933a597..e11be1e 100644
--- a/debuggerd/libdebuggerd/tombstone.cpp
+++ b/debuggerd/libdebuggerd/tombstone.cpp
@@ -102,18 +102,24 @@
if (!cause.empty()) _LOG(log, logtype::HEADER, "Cause: %s\n", cause.c_str());
}
-static void dump_signal_info(log_t* log, const siginfo_t* si) {
+static void dump_signal_info(log_t* log, const ThreadInfo& thread_info) {
char addr_desc[32]; // ", fault addr 0x1234"
- if (signal_has_si_addr(si->si_signo, si->si_code)) {
- snprintf(addr_desc, sizeof(addr_desc), "%p", si->si_addr);
+ if (signal_has_si_addr(thread_info.siginfo)) {
+ snprintf(addr_desc, sizeof(addr_desc), "%p", thread_info.siginfo->si_addr);
} else {
snprintf(addr_desc, sizeof(addr_desc), "--------");
}
- _LOG(log, logtype::HEADER, "signal %d (%s), code %d (%s), fault addr %s\n", si->si_signo,
- get_signame(si->si_signo), si->si_code, get_sigcode(si->si_signo, si->si_code), addr_desc);
+ char sender_desc[32] = {}; // " from pid 1234, uid 666"
+ if (signal_has_sender(thread_info.siginfo, thread_info.pid)) {
+ get_signal_sender(sender_desc, sizeof(sender_desc), thread_info.siginfo);
+ }
- dump_probable_cause(log, si);
+ _LOG(log, logtype::HEADER, "signal %d (%s), code %d (%s%s), fault addr %s\n",
+ thread_info.siginfo->si_signo, get_signame(thread_info.siginfo),
+ thread_info.siginfo->si_code, get_sigcode(thread_info.siginfo), sender_desc, addr_desc);
+
+ dump_probable_cause(log, thread_info.siginfo);
}
static void dump_thread_info(log_t* log, const ThreadInfo& thread_info) {
@@ -239,19 +245,22 @@
return;
}
- char msg[512];
- if (length >= sizeof(msg)) {
- _LOG(log, logtype::HEADER, "Abort message too long: claimed length = %zd\n", length);
+ // The length field includes the length of the length field itself.
+ if (length < sizeof(size_t)) {
+ _LOG(log, logtype::HEADER, "Abort message header malformed: claimed length = %zd\n", length);
return;
}
- if (!process_memory->ReadFully(address + sizeof(length), msg, length)) {
+ length -= sizeof(size_t);
+
+ // The abort message should be null terminated already, but reserve a spot for NUL just in case.
+ std::vector<char> msg(length + 1);
+ if (!process_memory->ReadFully(address + sizeof(length), &msg[0], length)) {
_LOG(log, logtype::HEADER, "Failed to read abort message: %s\n", strerror(errno));
return;
}
- msg[length] = '\0';
- _LOG(log, logtype::HEADER, "Abort message: '%s'\n", msg);
+ _LOG(log, logtype::HEADER, "Abort message: '%s'\n", &msg[0]);
}
static void dump_all_maps(log_t* log, BacktraceMap* map, Memory* process_memory, uint64_t addr) {
@@ -409,7 +418,7 @@
dump_thread_info(log, thread_info);
if (thread_info.siginfo) {
- dump_signal_info(log, thread_info.siginfo);
+ dump_signal_info(log, thread_info);
}
if (primary_thread) {
@@ -439,7 +448,7 @@
if (map) {
uint64_t addr = 0;
siginfo_t* si = thread_info.siginfo;
- if (signal_has_si_addr(si->si_signo, si->si_code)) {
+ if (signal_has_si_addr(si)) {
addr = reinterpret_cast<uint64_t>(si->si_addr);
}
dump_all_maps(log, map, process_memory, addr);
diff --git a/debuggerd/libdebuggerd/utility.cpp b/debuggerd/libdebuggerd/utility.cpp
index d153865..1f6f3c8 100644
--- a/debuggerd/libdebuggerd/utility.cpp
+++ b/debuggerd/libdebuggerd/utility.cpp
@@ -74,25 +74,22 @@
&& (log->crashed_tid == log->current_tid);
static bool write_to_kmsg = should_write_to_kmsg();
- char buf[512];
+ std::string msg;
va_list ap;
va_start(ap, fmt);
- vsnprintf(buf, sizeof(buf), fmt, ap);
+ android::base::StringAppendV(&msg, fmt, ap);
va_end(ap);
- size_t len = strlen(buf);
- if (len <= 0) {
- return;
- }
+ if (msg.empty()) return;
if (write_to_tombstone) {
- TEMP_FAILURE_RETRY(write(log->tfd, buf, len));
+ TEMP_FAILURE_RETRY(write(log->tfd, msg.c_str(), msg.size()));
}
if (write_to_logcat) {
- __android_log_buf_write(LOG_ID_CRASH, ANDROID_LOG_FATAL, LOG_TAG, buf);
+ __android_log_buf_write(LOG_ID_CRASH, ANDROID_LOG_FATAL, LOG_TAG, msg.c_str());
if (log->amfd_data != nullptr) {
- *log->amfd_data += buf;
+ *log->amfd_data += msg;
}
if (write_to_kmsg) {
@@ -100,11 +97,11 @@
if (kmsg_fd.get() >= 0) {
// Our output might contain newlines which would otherwise be handled by the android logger.
// Split the lines up ourselves before sending to the kernel logger.
- if (buf[len - 1] == '\n') {
- buf[len - 1] = '\0';
+ if (msg.back() == '\n') {
+ msg.back() = '\0';
}
- std::vector<std::string> fragments = android::base::Split(buf, "\n");
+ std::vector<std::string> fragments = android::base::Split(msg, "\n");
for (const std::string& fragment : fragments) {
static constexpr char prefix[] = "<3>DEBUG: ";
struct iovec iov[3];
@@ -257,13 +254,13 @@
}
}
-bool signal_has_si_addr(int si_signo, int si_code) {
+bool signal_has_si_addr(const siginfo_t* si) {
// Manually sent signals won't have si_addr.
- if (si_code == SI_USER || si_code == SI_QUEUE || si_code == SI_TKILL) {
+ if (si->si_code == SI_USER || si->si_code == SI_QUEUE || si->si_code == SI_TKILL) {
return false;
}
- switch (si_signo) {
+ switch (si->si_signo) {
case SIGBUS:
case SIGFPE:
case SIGILL:
@@ -275,8 +272,16 @@
}
}
-const char* get_signame(int sig) {
- switch (sig) {
+bool signal_has_sender(const siginfo_t* si, pid_t caller_pid) {
+ return SI_FROMUSER(si) && (si->si_pid != 0) && (si->si_pid != caller_pid);
+}
+
+void get_signal_sender(char* buf, size_t n, const siginfo_t* si) {
+ snprintf(buf, n, " from pid %d, uid %d", si->si_pid, si->si_uid);
+}
+
+const char* get_signame(const siginfo_t* si) {
+ switch (si->si_signo) {
case SIGABRT: return "SIGABRT";
case SIGBUS: return "SIGBUS";
case SIGFPE: return "SIGFPE";
@@ -293,11 +298,11 @@
}
}
-const char* get_sigcode(int signo, int code) {
+const char* get_sigcode(const siginfo_t* si) {
// Try the signal-specific codes...
- switch (signo) {
+ switch (si->si_signo) {
case SIGILL:
- switch (code) {
+ switch (si->si_code) {
case ILL_ILLOPC: return "ILL_ILLOPC";
case ILL_ILLOPN: return "ILL_ILLOPN";
case ILL_ILLADR: return "ILL_ILLADR";
@@ -310,7 +315,7 @@
static_assert(NSIGILL == ILL_BADSTK, "missing ILL_* si_code");
break;
case SIGBUS:
- switch (code) {
+ switch (si->si_code) {
case BUS_ADRALN: return "BUS_ADRALN";
case BUS_ADRERR: return "BUS_ADRERR";
case BUS_OBJERR: return "BUS_OBJERR";
@@ -320,7 +325,7 @@
static_assert(NSIGBUS == BUS_MCEERR_AO, "missing BUS_* si_code");
break;
case SIGFPE:
- switch (code) {
+ switch (si->si_code) {
case FPE_INTDIV: return "FPE_INTDIV";
case FPE_INTOVF: return "FPE_INTOVF";
case FPE_FLTDIV: return "FPE_FLTDIV";
@@ -333,7 +338,7 @@
static_assert(NSIGFPE == FPE_FLTSUB, "missing FPE_* si_code");
break;
case SIGSEGV:
- switch (code) {
+ switch (si->si_code) {
case SEGV_MAPERR: return "SEGV_MAPERR";
case SEGV_ACCERR: return "SEGV_ACCERR";
#if defined(SEGV_BNDERR)
@@ -353,21 +358,21 @@
break;
#if defined(SYS_SECCOMP) // Our glibc is too old, and we build this for the host too.
case SIGSYS:
- switch (code) {
+ switch (si->si_code) {
case SYS_SECCOMP: return "SYS_SECCOMP";
}
static_assert(NSIGSYS == SYS_SECCOMP, "missing SYS_* si_code");
break;
#endif
case SIGTRAP:
- switch (code) {
+ switch (si->si_code) {
case TRAP_BRKPT: return "TRAP_BRKPT";
case TRAP_TRACE: return "TRAP_TRACE";
case TRAP_BRANCH: return "TRAP_BRANCH";
case TRAP_HWBKPT: return "TRAP_HWBKPT";
}
- if ((code & 0xff) == SIGTRAP) {
- switch ((code >> 8) & 0xff) {
+ if ((si->si_code & 0xff) == SIGTRAP) {
+ switch ((si->si_code >> 8) & 0xff) {
case PTRACE_EVENT_FORK:
return "PTRACE_EVENT_FORK";
case PTRACE_EVENT_VFORK:
@@ -390,7 +395,7 @@
break;
}
// Then the other codes...
- switch (code) {
+ switch (si->si_code) {
case SI_USER: return "SI_USER";
case SI_KERNEL: return "SI_KERNEL";
case SI_QUEUE: return "SI_QUEUE";
diff --git a/demangle/Android.bp b/demangle/Android.bp
index 8d5b135..cf6abfd 100644
--- a/demangle/Android.bp
+++ b/demangle/Android.bp
@@ -78,4 +78,9 @@
shared_libs: [
"libdemangle",
],
+
+ test_suites: ["device-tests"],
+ required: [
+ "libdemangle",
+ ],
}
diff --git a/demangle/Android.mk b/demangle/Android.mk
index e3cfc2a..d8082a9 100644
--- a/demangle/Android.mk
+++ b/demangle/Android.mk
@@ -19,7 +19,6 @@
include $(CLEAR_VARS)
LOCAL_MODULE := demangle_fuzzer
-LOCAL_MODULE_TAGS := optional
LOCAL_SRC_FILES := \
Demangler.cpp \
demangle_fuzzer.cpp \
diff --git a/diagnose_usb/Android.bp b/diagnose_usb/Android.bp
new file mode 100644
index 0000000..a7ecf37
--- /dev/null
+++ b/diagnose_usb/Android.bp
@@ -0,0 +1,13 @@
+cc_library_static {
+ name: "libdiagnose_usb",
+ cflags: ["-Wall", "-Wextra", "-Werror"],
+ host_supported: true,
+ target: {
+ windows: {
+ enabled: true,
+ },
+ },
+ srcs: ["diagnose_usb.cpp"],
+ export_include_dirs: ["include"],
+ static_libs: ["libbase"],
+}
diff --git a/diagnose_usb/OWNERS b/diagnose_usb/OWNERS
new file mode 100644
index 0000000..643b448
--- /dev/null
+++ b/diagnose_usb/OWNERS
@@ -0,0 +1,2 @@
+jmgao@google.com
+yabinc@google.com
diff --git a/adb/diagnose_usb.cpp b/diagnose_usb/diagnose_usb.cpp
similarity index 97%
rename from adb/diagnose_usb.cpp
rename to diagnose_usb/diagnose_usb.cpp
index 9f721bf..5695ece 100644
--- a/adb/diagnose_usb.cpp
+++ b/diagnose_usb/diagnose_usb.cpp
@@ -33,7 +33,7 @@
// Returns a message describing any potential problems we find with udev, or an empty string if we
// can't find plugdev information (i.e. udev is not installed).
static std::string GetUdevProblem() {
-#if defined(__linux__)
+#if defined(__linux__) && !defined(__BIONIC__)
errno = 0;
group* plugdev_group = getgrnam("plugdev");
diff --git a/adb/diagnose_usb.h b/diagnose_usb/include/diagnose_usb.h
similarity index 100%
rename from adb/diagnose_usb.h
rename to diagnose_usb/include/diagnose_usb.h
diff --git a/fastboot/Android.mk b/fastboot/Android.mk
index 944b00b..983e195 100644
--- a/fastboot/Android.mk
+++ b/fastboot/Android.mk
@@ -16,14 +16,35 @@
include $(LOCAL_PATH)/../platform_tools_tool_version.mk
+fastboot_cflags := -Wall -Wextra -Werror -Wunreachable-code
+fastboot_cflags += -DFASTBOOT_VERSION="\"$(tool_version)\""
+fastboot_cflags_darwin := -Wno-unused-parameter
+fastboot_ldlibs_darwin := -lpthread -framework CoreFoundation -framework IOKit -framework Carbon
+fastboot_ldlibs_windows := -lws2_32
+# Don't add anything here, we don't want additional shared dependencies
+# on the host fastboot tool, and shared libraries that link against libc++
+# will violate ODR.
+fastboot_shared_libs :=
+fastboot_static_libs := \
+ libziparchive \
+ libsparse \
+ libutils \
+ liblog \
+ libz \
+ libdiagnose_usb \
+ libbase \
+ libcutils \
+ libgtest_host \
+
+fastboot_stl := libc++_static
+
+#
+# Build host libfastboot.
+#
+
include $(CLEAR_VARS)
-
-LOCAL_CFLAGS += -DFASTBOOT_VERSION="\"$(tool_version)\""
-
-LOCAL_C_INCLUDES := \
- $(LOCAL_PATH)/../adb \
-
-LOCAL_HEADER_LIBRARIES := bootimg_headers
+LOCAL_MODULE := libfastboot
+LOCAL_MODULE_HOST_OS := darwin linux windows
LOCAL_SRC_FILES := \
bootimg_utils.cpp \
@@ -36,92 +57,83 @@
udp.cpp \
util.cpp \
-LOCAL_MODULE := fastboot
-LOCAL_MODULE_TAGS := debug
-LOCAL_MODULE_HOST_OS := darwin linux windows
-LOCAL_CFLAGS += -Wall -Wextra -Werror -Wunreachable-code
-LOCAL_REQUIRED_MODULES := mke2fs make_f2fs
-
-LOCAL_SRC_FILES_linux := usb_linux.cpp
-LOCAL_STATIC_LIBRARIES_linux := libselinux
-LOCAL_REQUIRED_MODULES_linux := e2fsdroid mke2fs.conf sload_f2fs
-
LOCAL_SRC_FILES_darwin := usb_osx.cpp
-LOCAL_STATIC_LIBRARIES_darwin := libselinux
-LOCAL_REQUIRED_MODULES_darwin := e2fsdroid mke2fs.conf sload_f2fs
-LOCAL_LDLIBS_darwin := -lpthread -framework CoreFoundation -framework IOKit -framework Carbon
-LOCAL_CFLAGS_darwin := -Wno-unused-parameter
-
+LOCAL_SRC_FILES_linux := usb_linux.cpp
LOCAL_SRC_FILES_windows := usb_windows.cpp
-LOCAL_SHARED_LIBRARIES_windows := AdbWinApi
-LOCAL_REQUIRED_MODULES_windows := AdbWinUsbApi
-LOCAL_LDLIBS_windows := -lws2_32
+
LOCAL_C_INCLUDES_windows := development/host/windows/usb/api
+LOCAL_CFLAGS := $(fastboot_cflags)
+LOCAL_CFLAGS_darwin := $(fastboot_cflags_darwin)
+LOCAL_CXX_STL := $(fastboot_stl)
+LOCAL_HEADER_LIBRARIES := bootimg_headers
+LOCAL_LDLIBS_darwin := $(fastboot_ldlibs_darwin)
+LOCAL_LDLIBS_windows := $(fastboot_ldlibs_windows)
+LOCAL_SHARED_LIBRARIES := $(fastboot_shared_libs)
+LOCAL_STATIC_LIBRARIES := $(fastboot_static_libs)
+include $(BUILD_HOST_STATIC_LIBRARY)
-LOCAL_STATIC_LIBRARIES := \
- libziparchive \
- libsparse \
- libutils \
- liblog \
- libz \
- libdiagnose_usb \
- libbase \
- libcutils \
- libgtest_host \
+#
+# Build host fastboot / fastboot.exe
+#
-LOCAL_CXX_STL := libc++_static
+include $(CLEAR_VARS)
+LOCAL_MODULE := fastboot
+LOCAL_MODULE_HOST_OS := darwin linux windows
-# Don't add anything here, we don't want additional shared dependencies
-# on the host fastboot tool, and shared libraries that link against libc++
-# will violate ODR
-LOCAL_SHARED_LIBRARIES :=
-
+LOCAL_CFLAGS := $(fastboot_cflags)
+LOCAL_CFLAGS_darwin := $(fastboot_cflags_darwin)
+LOCAL_CXX_STL := $(fastboot_stl)
+LOCAL_HEADER_LIBRARIES := bootimg_headers
+LOCAL_LDLIBS_darwin := $(fastboot_ldlibs_darwin)
+LOCAL_LDLIBS_windows := $(fastboot_ldlibs_windows)
+LOCAL_REQUIRED_MODULES := mke2fs make_f2fs
+LOCAL_REQUIRED_MODULES_darwin := e2fsdroid mke2fs.conf sload_f2fs
+LOCAL_REQUIRED_MODULES_linux := e2fsdroid mke2fs.conf sload_f2fs
+LOCAL_REQUIRED_MODULES_windows := AdbWinUsbApi
+LOCAL_SRC_FILES := main.cpp
+LOCAL_SHARED_LIBRARIES := $(fastboot_shared_libs)
+LOCAL_SHARED_LIBRARIES_windows := AdbWinApi
+LOCAL_STATIC_LIBRARIES := libfastboot $(fastboot_static_libs)
include $(BUILD_HOST_EXECUTABLE)
-my_dist_files := $(LOCAL_BUILT_MODULE)
-my_dist_files += $(HOST_OUT_EXECUTABLES)/mke2fs$(HOST_EXECUTABLE_SUFFIX)
-my_dist_files += $(HOST_OUT_EXECUTABLES)/e2fsdroid$(HOST_EXECUTABLE_SUFFIX)
-my_dist_files += $(HOST_OUT_EXECUTABLES)/make_f2fs$(HOST_EXECUTABLE_SUFFIX)
-my_dist_files += $(HOST_OUT_EXECUTABLES)/sload_f2fs$(HOST_EXECUTABLE_SUFFIX)
+#
+# Package fastboot-related executables.
+#
+
+my_dist_files := $(HOST_OUT_EXECUTABLES)/fastboot
+my_dist_files += $(HOST_OUT_EXECUTABLES)/mke2fs
+my_dist_files += $(HOST_OUT_EXECUTABLES)/e2fsdroid
+my_dist_files += $(HOST_OUT_EXECUTABLES)/make_f2fs
+my_dist_files += $(HOST_OUT_EXECUTABLES)/sload_f2fs
$(call dist-for-goals,dist_files sdk win_sdk,$(my_dist_files))
ifdef HOST_CROSS_OS
-# Archive fastboot.exe for win_sdk build.
-$(call dist-for-goals,win_sdk,$(ALL_MODULES.host_cross_fastboot.BUILT))
+$(call dist-for-goals,dist_files sdk win_sdk,$(ALL_MODULES.host_cross_fastboot.BUILT))
endif
my_dist_files :=
-ifeq ($(HOST_OS),linux)
-include $(CLEAR_VARS)
-LOCAL_SRC_FILES := usbtest.cpp usb_linux.cpp util.cpp
-LOCAL_MODULE := usbtest
-LOCAL_CFLAGS := -Werror
-LOCAL_STATIC_LIBRARIES := libbase
-include $(BUILD_HOST_EXECUTABLE)
-endif
+#
+# Build host fastboot_test.
+#
-# fastboot_test
-# =========================================================
include $(CLEAR_VARS)
-
LOCAL_MODULE := fastboot_test
LOCAL_MODULE_HOST_OS := darwin linux windows
+LOCAL_MODULE_HOST_CROSS_ARCH := x86 # Avoid trying to build for win64.
LOCAL_SRC_FILES := \
- socket.cpp \
+ fastboot_test.cpp \
socket_mock.cpp \
socket_test.cpp \
- tcp.cpp \
tcp_test.cpp \
- udp.cpp \
udp_test.cpp \
-LOCAL_STATIC_LIBRARIES := libbase libcutils
-
-LOCAL_CFLAGS += -Wall -Wextra -Werror -Wunreachable-code
-
-LOCAL_LDLIBS_darwin := -lpthread -framework CoreFoundation -framework IOKit -framework Carbon
-LOCAL_CFLAGS_darwin := -Wno-unused-parameter
-
-LOCAL_LDLIBS_windows := -lws2_32
-
+LOCAL_CFLAGS := $(fastboot_cflags)
+LOCAL_CFLAGS_darwin := $(fastboot_cflags_darwin)
+LOCAL_CXX_STL := $(fastboot_stl)
+LOCAL_HEADER_LIBRARIES := bootimg_headers
+LOCAL_LDLIBS_darwin := $(fastboot_ldlibs_darwin)
+LOCAL_LDLIBS_windows := $(fastboot_ldlibs_windows)
+LOCAL_SHARED_LIBRARIES := $(fastboot_shared_libs)
+LOCAL_SHARED_LIBRARIES_windows := AdbWinApi
+LOCAL_STATIC_LIBRARIES := libfastboot $(fastboot_static_libs)
include $(BUILD_HOST_NATIVE_TEST)
diff --git a/fastboot/bootimg_utils.cpp b/fastboot/bootimg_utils.cpp
index 2e8c334..c9814e4 100644
--- a/fastboot/bootimg_utils.cpp
+++ b/fastboot/bootimg_utils.cpp
@@ -34,16 +34,15 @@
#include <stdlib.h>
#include <string.h>
-void bootimg_set_cmdline(boot_img_hdr_v1* h, const char* cmdline) {
- if (strlen(cmdline) >= sizeof(h->cmdline)) die("command line too large: %zu", strlen(cmdline));
- strcpy(reinterpret_cast<char*>(h->cmdline), cmdline);
+void bootimg_set_cmdline(boot_img_hdr_v1* h, const std::string& cmdline) {
+ if (cmdline.size() >= sizeof(h->cmdline)) die("command line too large: %zu", cmdline.size());
+ strcpy(reinterpret_cast<char*>(h->cmdline), cmdline.c_str());
}
-boot_img_hdr_v1* mkbootimg(void* kernel, int64_t kernel_size, off_t kernel_offset, void* ramdisk,
- int64_t ramdisk_size, off_t ramdisk_offset, void* second,
- int64_t second_size, off_t second_offset, size_t page_size, size_t base,
- off_t tags_offset, uint32_t header_version, int64_t* bootimg_size) {
- size_t page_mask = page_size - 1;
+boot_img_hdr_v1* mkbootimg(void* kernel, int64_t kernel_size, void* ramdisk, int64_t ramdisk_size,
+ void* second, int64_t second_size, size_t base,
+ const boot_img_hdr_v1& src, int64_t* bootimg_size) {
+ const size_t page_mask = src.page_size - 1;
int64_t header_actual = (sizeof(boot_img_hdr_v1) + page_mask) & (~page_mask);
int64_t kernel_actual = (kernel_size + page_mask) & (~page_mask);
@@ -53,30 +52,26 @@
*bootimg_size = header_actual + kernel_actual + ramdisk_actual + second_actual;
boot_img_hdr_v1* hdr = reinterpret_cast<boot_img_hdr_v1*>(calloc(*bootimg_size, 1));
- if (hdr == nullptr) {
- return hdr;
- }
+ if (hdr == nullptr) die("couldn't allocate boot image: %" PRId64 " bytes", *bootimg_size);
+ *hdr = src;
memcpy(hdr->magic, BOOT_MAGIC, BOOT_MAGIC_SIZE);
hdr->kernel_size = kernel_size;
hdr->ramdisk_size = ramdisk_size;
hdr->second_size = second_size;
- hdr->kernel_addr = base + kernel_offset;
- hdr->ramdisk_addr = base + ramdisk_offset;
- hdr->second_addr = base + second_offset;
- hdr->tags_addr = base + tags_offset;
+ hdr->kernel_addr += base;
+ hdr->ramdisk_addr += base;
+ hdr->second_addr += base;
+ hdr->tags_addr += base;
- hdr->page_size = page_size;
-
- if (header_version) {
- hdr->header_version = header_version;
+ if (hdr->header_version != 0) {
hdr->header_size = sizeof(boot_img_hdr_v1);
}
- memcpy(hdr->magic + page_size, kernel, kernel_size);
- memcpy(hdr->magic + page_size + kernel_actual, ramdisk, ramdisk_size);
- memcpy(hdr->magic + page_size + kernel_actual + ramdisk_actual, second, second_size);
+ memcpy(hdr->magic + hdr->page_size, kernel, kernel_size);
+ memcpy(hdr->magic + hdr->page_size + kernel_actual, ramdisk, ramdisk_size);
+ memcpy(hdr->magic + hdr->page_size + kernel_actual + ramdisk_actual, second, second_size);
return hdr;
}
diff --git a/fastboot/bootimg_utils.h b/fastboot/bootimg_utils.h
index d3993f5..fe805b0 100644
--- a/fastboot/bootimg_utils.h
+++ b/fastboot/bootimg_utils.h
@@ -26,17 +26,15 @@
* SUCH DAMAGE.
*/
-#ifndef _FASTBOOT_BOOTIMG_UTILS_H_
-#define _FASTBOOT_BOOTIMG_UTILS_H_
+#pragma once
#include <bootimg.h>
#include <inttypes.h>
#include <sys/types.h>
-void bootimg_set_cmdline(boot_img_hdr_v1* h, const char* cmdline);
-boot_img_hdr_v1* mkbootimg(void* kernel, int64_t kernel_size, off_t kernel_offset, void* ramdisk,
- int64_t ramdisk_size, off_t ramdisk_offset, void* second,
- int64_t second_size, off_t second_offset, size_t page_size, size_t base,
- off_t tags_offset, uint32_t header_version, int64_t* bootimg_size);
+#include <string>
-#endif
+boot_img_hdr_v1* mkbootimg(void* kernel, int64_t kernel_size, void* ramdisk, int64_t ramdisk_size,
+ void* second, int64_t second_size, size_t base,
+ const boot_img_hdr_v1& src, int64_t* bootimg_size);
+void bootimg_set_cmdline(boot_img_hdr_v1* h, const std::string& cmdline);
diff --git a/fastboot/engine.cpp b/fastboot/engine.cpp
index 60b7124..f271d09 100644
--- a/fastboot/engine.cpp
+++ b/fastboot/engine.cpp
@@ -42,6 +42,8 @@
#include <android-base/stringprintf.h>
+#include "transport.h"
+
enum Op {
OP_DOWNLOAD,
OP_COMMAND,
@@ -109,32 +111,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 +144,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 +272,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 +291,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 +314,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 +336,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 e89586f..9463cc9 100644
--- a/fastboot/fastboot.cpp
+++ b/fastboot/fastboot.cpp
@@ -76,22 +76,18 @@
char cur_product[FB_RESPONSE_SZ + 1];
static const char* serial = nullptr;
-static const char* cmdline = nullptr;
-static unsigned short vendor_id = 0;
-static int long_listing = 0;
+
+static bool g_long_listing = false;
// Don't resparse files in too-big chunks.
// libsparse will support INT_MAX, but this results in large allocations, so
// let's keep it at 1GB to avoid memory pressure on the host.
static constexpr int64_t RESPARSE_LIMIT = 1 * 1024 * 1024 * 1024;
-static int64_t sparse_limit = -1;
+static uint64_t sparse_limit = 0;
static int64_t target_sparse_limit = -1;
-static unsigned page_size = 2048;
-static unsigned base_addr = 0x10000000;
-static unsigned kernel_offset = 0x00008000;
-static unsigned ramdisk_offset = 0x01000000;
-static unsigned second_offset = 0x00f00000;
-static unsigned tags_offset = 0x00000100;
+static unsigned g_base_addr = 0x10000000;
+static boot_img_hdr_v1 g_boot_img_hdr = {};
+static std::string g_cmdline;
static bool g_disable_verity = false;
static bool g_disable_verification = false;
@@ -193,11 +189,6 @@
}
static int match_fastboot_with_serial(usb_ifc_info* info, const char* local_serial) {
- // Require a matching vendor id if the user specified one with -i.
- if (vendor_id != 0 && info->dev_vendor != vendor_id) {
- return -1;
- }
-
if (info->ifc_class != 0xff || info->ifc_subclass != 0x42 || info->ifc_protocol != 0x03) {
return -1;
}
@@ -223,7 +214,7 @@
serial = "????????????";
}
// output compatible with "adb devices"
- if (!long_listing) {
+ if (!g_long_listing) {
printf("%s\tfastboot", serial.c_str());
} else {
printf("%-22s fastboot", serial.c_str());
@@ -238,7 +229,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 +261,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,125 +317,87 @@
// 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"
+ " --cmdline 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"
+ " --os-version MAJOR[.MINOR[.PATCH]]\n"
+ " Set boot image OS version (default: 0.0.0).\n"
+ " --os-patch-level YYYY-MM-DD\n"
+ " Set boot image OS security patch level.\n"
+ // TODO: still missing: `second_addr`, `name`, `id`, `recovery_dtbo_*`.
+ "\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"
+ " -s SERIAL Specify a USB device.\n"
+ " -s tcp|udp:HOST[:PORT] Specify a network device.\n"
+ " -S SIZE[K|M|G] Break into sparse files no larger than SIZE.\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;
}
static void* load_bootable_image(const std::string& kernel, const std::string& ramdisk,
- const std::string& second_stage, int64_t* sz,
- const char* cmdline, uint32_t header_version) {
+ const std::string& second_stage, int64_t* sz) {
int64_t ksize;
void* kdata = load_file(kernel.c_str(), &ksize);
if (kdata == nullptr) die("cannot load '%s': %s", kernel.c_str(), strerror(errno));
@@ -456,7 +407,9 @@
die("cannot load '%s': too short", kernel.c_str());
}
if (!memcmp(kdata, BOOT_MAGIC, BOOT_MAGIC_SIZE)) {
- if (cmdline) bootimg_set_cmdline(reinterpret_cast<boot_img_hdr_v1*>(kdata), cmdline);
+ if (!g_cmdline.empty()) {
+ bootimg_set_cmdline(reinterpret_cast<boot_img_hdr_v1*>(kdata), g_cmdline);
+ }
if (!ramdisk.empty()) die("cannot boot a boot.img *and* ramdisk");
@@ -479,16 +432,12 @@
}
fprintf(stderr,"creating boot image...\n");
- int64_t bsize = 0;
- boot_img_hdr_v1* bdata = mkbootimg(kdata, ksize, kernel_offset,
- rdata, rsize, ramdisk_offset,
- sdata, ssize, second_offset,
- page_size, base_addr, tags_offset, header_version, &bsize);
+ boot_img_hdr_v1* bdata = mkbootimg(kdata, ksize, rdata, rsize, sdata, ssize,
+ g_base_addr, g_boot_img_hdr, sz);
if (bdata == nullptr) die("failed to create boot.img");
- if (cmdline) bootimg_set_cmdline(bdata, cmdline);
- fprintf(stderr, "creating boot image - %" PRId64 " bytes\n", bsize);
- *sz = bsize;
+ if (!g_cmdline.empty()) bootimg_set_cmdline(bdata, g_cmdline);
+ fprintf(stderr, "creating boot image - %" PRId64 " bytes\n", *sz);
return bdata;
}
@@ -542,7 +491,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());
}
@@ -558,18 +507,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;
@@ -579,16 +526,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;
@@ -609,10 +551,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;
@@ -754,10 +693,14 @@
fb_queue_notice("--------------------------------------------");
}
-static struct sparse_file** load_sparse_files(int fd, int max_size) {
+static struct sparse_file** load_sparse_files(int fd, int64_t max_size) {
struct sparse_file* s = sparse_file_import_auto(fd, false, true);
if (!s) die("cannot sparse read file");
+ if (max_size <= 0 || max_size > std::numeric_limits<uint32_t>::max()) {
+ die("invalid max size %" PRId64, max_size);
+ }
+
int files = sparse_file_resparse(s, max_size, nullptr, 0);
if (files < 0) die("Failed to resparse");
@@ -773,8 +716,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;
}
@@ -786,20 +729,15 @@
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;
}
static int64_t get_sparse_limit(Transport* transport, int64_t size) {
- int64_t limit;
-
- if (sparse_limit == 0) {
- return 0;
- } else if (sparse_limit > 0) {
- limit = sparse_limit;
- } else {
+ int64_t limit = sparse_limit;
+ if (limit == 0) {
+ // Unlimited, so see what the target device's limit is.
+ // TODO: shouldn't we apply this limit even if you've used -S?
if (target_sparse_limit == -1) {
target_sparse_limit = get_target_sparse_limit(transport);
}
@@ -817,17 +755,6 @@
return 0;
}
-// Until we get lazy inode table init working in make_ext4fs, we need to
-// erase partitions of type ext4 before flashing a filesystem so no stale
-// inodes are left lying around. Otherwise, e2fsck gets very upset.
-static bool needs_erase(Transport* transport, const char* partition) {
- std::string partition_type;
- if (!fb_getvar(transport, std::string("partition-type:") + partition, &partition_type)) {
- return false;
- }
- return partition_type == "ext4";
-}
-
static bool load_buf_fd(Transport* transport, int fd, struct fastboot_buffer* buf) {
int64_t sz = get_file_size(fd);
if (sz == -1) {
@@ -879,10 +806,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)) {
@@ -944,46 +868,18 @@
}
}
-static std::string get_current_slot(Transport* transport)
-{
+static std::string get_current_slot(Transport* transport) {
std::string current_slot;
- if (fb_getvar(transport, "current-slot", ¤t_slot)) {
- if (current_slot == "_a") return "a"; // Legacy support
- if (current_slot == "_b") return "b"; // Legacy support
- return current_slot;
- }
- return "";
-}
-
-// Legacy support
-static std::vector<std::string> get_suffixes_obsolete(Transport* transport) {
- std::vector<std::string> suffixes;
- std::string suffix_list;
- if (!fb_getvar(transport, "slot-suffixes", &suffix_list)) {
- return suffixes;
- }
- suffixes = android::base::Split(suffix_list, ",");
- // Unfortunately some devices will return an error message in the
- // guise of a valid value. If we only see only one suffix, it's probably
- // not real.
- if (suffixes.size() == 1) {
- suffixes.clear();
- }
- return suffixes;
-}
-
-// Legacy support
-static bool supports_AB_obsolete(Transport* transport) {
- return !get_suffixes_obsolete(transport).empty();
+ if (!fb_getvar(transport, "current-slot", ¤t_slot)) return "";
+ return current_slot;
}
static int get_slot_count(Transport* transport) {
std::string var;
- int count;
- if (!fb_getvar(transport, "slot-count", &var)) {
- if (supports_AB_obsolete(transport)) return 2; // Legacy support
+ int count = 0;
+ if (!fb_getvar(transport, "slot-count", &var) || !android::base::ParseInt(var, &count)) {
+ return 0;
}
- if (!android::base::ParseInt(var, &count)) return 0;
return count;
}
@@ -1013,8 +909,6 @@
static std::string verify_slot(Transport* transport, const std::string& slot_name, bool allow_all) {
std::string slot = slot_name;
- if (slot == "_a") slot = "a"; // Legacy support
- if (slot == "_b") slot = "b"; // Legacy support
if (slot == "all") {
if (allow_all) {
return "all";
@@ -1126,25 +1020,19 @@
// Sets slot_override as the active slot. If slot_override is blank,
// set current slot as active instead. This clears slot-unbootable.
static void set_active(Transport* transport, const std::string& slot_override) {
- std::string separator = "";
- if (!supports_AB(transport)) {
- if (supports_AB_obsolete(transport)) {
- separator = "_"; // Legacy support
- } else {
- return;
- }
- }
+ if (!supports_AB(transport)) return;
+
if (slot_override != "") {
- fb_set_active(separator + slot_override);
+ fb_set_active(slot_override);
} else {
std::string current_slot = get_current_slot(transport);
if (current_slot != "") {
- fb_set_active(separator + current_slot);
+ fb_set_active(current_slot);
}
}
}
-static void do_update(Transport* transport, const char* filename, const std::string& slot_override, bool erase_first, bool skip_secondary) {
+static void do_update(Transport* transport, const char* filename, const std::string& slot_override, bool skip_secondary) {
queue_info_dump();
fb_queue_query_save("product", cur_product, sizeof(cur_product));
@@ -1202,9 +1090,6 @@
auto update = [&](const std::string& partition) {
do_update_signature(zip, images[i].sig_name);
- if (erase_first && needs_erase(transport, partition.c_str())) {
- fb_queue_erase(partition);
- }
flash_buf(partition.c_str(), &buf);
/* not closing the fd here since the sparse code keeps the fd around
* but hasn't mmaped data yet. The temporary file will get cleaned up when the
@@ -1237,7 +1122,7 @@
fb_queue_command("signature", "installing signature");
}
-static void do_flashall(Transport* transport, const std::string& slot_override, int erase_first, bool skip_secondary) {
+static void do_flashall(Transport* transport, const std::string& slot_override, bool skip_secondary) {
std::string fname;
queue_info_dump();
@@ -1284,9 +1169,6 @@
auto flashall = [&](const std::string &partition) {
do_send_signature(fname.c_str());
- if (erase_first && needs_erase(transport, partition.c_str())) {
- fb_queue_erase(partition);
- }
flash_buf(partition.c_str(), &buf);
};
do_for_partitions(transport, images[i].part_name, slot, flashall, false);
@@ -1306,18 +1188,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");
@@ -1328,47 +1198,6 @@
fb_queue_command(command, "");
}
-static int64_t parse_num(const char *arg)
-{
- char *endptr;
- unsigned long long num;
-
- num = strtoull(arg, &endptr, 0);
- if (endptr == arg) {
- return -1;
- }
-
- if (*endptr == 'k' || *endptr == 'K') {
- if (num >= (-1ULL) / 1024) {
- return -1;
- }
- num *= 1024LL;
- endptr++;
- } else if (*endptr == 'm' || *endptr == 'M') {
- if (num >= (-1ULL) / (1024 * 1024)) {
- return -1;
- }
- num *= 1024LL * 1024LL;
- endptr++;
- } else if (*endptr == 'g' || *endptr == 'G') {
- if (num >= (-1ULL) / (1024 * 1024 * 1024)) {
- return -1;
- }
- num *= 1024LL * 1024LL * 1024LL;
- endptr++;
- }
-
- if (*endptr != '\0') {
- return -1;
- }
-
- if (num > INT64_MAX) {
- return -1;
- }
-
- return num;
-}
-
static std::string fb_fix_numeric_var(std::string var) {
// Some bootloaders (angler, for example), send spurious leading whitespace.
var = android::base::Trim(var);
@@ -1491,45 +1320,46 @@
fprintf(stderr, "FAILED (%s)\n", fb_get_error().c_str());
}
-int main(int argc, char **argv)
-{
+int FastBoot::Main(int argc, char* argv[]) {
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;
- bool erase_first = true;
bool set_fbe_marker = false;
void *data;
- uint32_t header_version = 0;
int64_t sz;
int longindex;
std::string slot_override;
std::string next_active;
+ g_boot_img_hdr.kernel_addr = 0x00008000;
+ g_boot_img_hdr.ramdisk_addr = 0x01000000;
+ g_boot_img_hdr.second_addr = 0x00f00000;
+ g_boot_img_hdr.tags_addr = 0x00000100;
+ g_boot_img_hdr.page_size = 2048;
+
const struct option longopts[] = {
- {"base", required_argument, 0, 'b'},
- {"kernel_offset", required_argument, 0, 'k'},
- {"kernel-offset", required_argument, 0, 'k'},
- {"page_size", required_argument, 0, 'n'},
- {"page-size", required_argument, 0, 'n'},
- {"ramdisk_offset", required_argument, 0, 'r'},
- {"ramdisk-offset", required_argument, 0, 'r'},
- {"tags_offset", required_argument, 0, 't'},
- {"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},
- {"disable-verity", no_argument, 0, 0},
+ {"base", required_argument, 0, 0},
+ {"cmdline", required_argument, 0, 0},
{"disable-verification", no_argument, 0, 0},
+ {"disable-verity", no_argument, 0, 0},
{"header-version", required_argument, 0, 0},
+ {"help", no_argument, 0, 'h'},
+ {"kernel-offset", required_argument, 0, 0},
+ {"os-patch-level", required_argument, 0, 0},
+ {"os-version", required_argument, 0, 0},
+ {"page-size", required_argument, 0, 0},
+ {"ramdisk-offset", required_argument, 0, 0},
+ {"set-active", optional_argument, 0, 'a'},
+ {"skip-reboot", no_argument, 0, 0},
+ {"skip-secondary", no_argument, 0, 0},
+ {"slot", required_argument, 0, 0},
+ {"tags-offset", required_argument, 0, 0},
+ {"unbuffered", no_argument, 0, 0},
+ {"verbose", no_argument, 0, 'v'},
+ {"version", no_argument, 0, 0},
#if !defined(_WIN32)
{"wipe-and-use-fbe", no_argument, 0, 0},
#endif
@@ -1538,100 +1368,84 @@
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);
- if (c < 0) {
- break;
- }
- /* Alphabetical cases */
- switch (c) {
- case 'a':
- wants_set_active = true;
- if (optarg)
- next_active = optarg;
- break;
- case 'b':
- base_addr = strtoul(optarg, 0, 16);
- break;
- case 'c':
- cmdline = optarg;
- break;
- case 'h':
- return show_help();
- case 'i': {
- char *endptr = nullptr;
- unsigned long val;
-
- val = strtoul(optarg, &endptr, 0);
- if (!endptr || *endptr != '\0' || (val & ~0xffff))
- die("invalid vendor id '%s'", optarg);
- vendor_id = (unsigned short)val;
- break;
- }
- case 'k':
- kernel_offset = strtoul(optarg, 0, 16);
- break;
- case 'l':
- long_listing = 1;
- break;
- case 'n':
- page_size = (unsigned)strtoul(optarg, nullptr, 0);
- if (!page_size) die("invalid page size");
- break;
- case 'r':
- ramdisk_offset = strtoul(optarg, 0, 16);
- break;
- case 't':
- tags_offset = strtoul(optarg, 0, 16);
- break;
- case 's':
- serial = optarg;
- break;
- case 'S':
- sparse_limit = parse_num(optarg);
- if (sparse_limit < 0) die("invalid sparse limit");
- break;
- case 'u':
- erase_first = false;
- break;
- case 'w':
- wants_wipe = true;
- break;
- case '?':
- return 1;
- case 0:
- if (strcmp("unbuffered", longopts[longindex].name) == 0) {
+ int c;
+ while ((c = getopt_long(argc, argv, "a::hls:S:vw", longopts, &longindex)) != -1) {
+ if (c == 0) {
+ std::string name{longopts[longindex].name};
+ if (name == "base") {
+ g_base_addr = strtoul(optarg, 0, 16);
+ } else if (name == "cmdline") {
+ g_cmdline = optarg;
+ } else if (name == "disable-verification") {
+ g_disable_verification = true;
+ } else if (name == "disable-verity") {
+ g_disable_verity = true;
+ } else if (name == "header-version") {
+ g_boot_img_hdr.header_version = strtoul(optarg, nullptr, 0);
+ } else if (name == "kernel-offset") {
+ g_boot_img_hdr.kernel_addr = strtoul(optarg, 0, 16);
+ } else if (name == "os-patch-level") {
+ ParseOsPatchLevel(&g_boot_img_hdr, optarg);
+ } else if (name == "os-version") {
+ ParseOsVersion(&g_boot_img_hdr, optarg);
+ } else if (name == "page-size") {
+ g_boot_img_hdr.page_size = strtoul(optarg, nullptr, 0);
+ if (g_boot_img_hdr.page_size == 0) die("invalid page size");
+ } else if (name == "ramdisk-offset") {
+ g_boot_img_hdr.ramdisk_addr = strtoul(optarg, 0, 16);
+ } else if (name == "skip-reboot") {
+ skip_reboot = true;
+ } else if (name == "skip-secondary") {
+ skip_secondary = true;
+ } else if (name == "slot") {
+ slot_override = optarg;
+ } else if (name == "tags-offset") {
+ g_boot_img_hdr.tags_addr = strtoul(optarg, 0, 16);
+ } else if (name == "unbuffered") {
setvbuf(stdout, nullptr, _IONBF, 0);
setvbuf(stderr, nullptr, _IONBF, 0);
- } else if (strcmp("version", longopts[longindex].name) == 0) {
+ } else if (name == "version") {
fprintf(stdout, "fastboot version %s\n", FASTBOOT_VERSION);
fprintf(stdout, "Installed as %s\n", android::base::GetExecutablePath().c_str());
return 0;
- } else if (strcmp("slot", longopts[longindex].name) == 0) {
- slot_override = std::string(optarg);
- } else if (strcmp("skip-secondary", longopts[longindex].name) == 0 ) {
- skip_secondary = true;
- } else if (strcmp("skip-reboot", longopts[longindex].name) == 0 ) {
- skip_reboot = true;
- } else if (strcmp("disable-verity", longopts[longindex].name) == 0 ) {
- g_disable_verity = true;
- } else if (strcmp("disable-verification", longopts[longindex].name) == 0 ) {
- g_disable_verification = true;
#if !defined(_WIN32)
- } else if (strcmp("wipe-and-use-fbe", longopts[longindex].name) == 0) {
+ } else if (name == "wipe-and-use-fbe") {
wants_wipe = true;
set_fbe_marker = true;
#endif
- } 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:
- abort();
+ } else {
+ switch (c) {
+ case 'a':
+ wants_set_active = true;
+ if (optarg) next_active = optarg;
+ break;
+ case 'h':
+ return show_help();
+ case 'l':
+ g_long_listing = true;
+ break;
+ case 's':
+ serial = optarg;
+ break;
+ case 'S':
+ if (!android::base::ParseByteCount(optarg, &sparse_limit)) {
+ die("invalid sparse limit %s", optarg);
+ }
+ break;
+ case 'v':
+ set_verbose();
+ break;
+ case 'w':
+ wants_wipe = true;
+ break;
+ case '?':
+ return 1;
+ default:
+ abort();
+ }
}
}
@@ -1656,9 +1470,6 @@
const double start = now();
- if (!supports_AB(transport) && supports_AB_obsolete(transport)) {
- fprintf(stderr, "Warning: Device A/B support is outdated. Bootloader update required.\n");
- }
if (slot_override != "") slot_override = verify_slot(transport, slot_override);
if (next_active != "") next_active = verify_slot(transport, next_active, false);
@@ -1715,9 +1526,6 @@
std::string partition = next_arg(&args);
auto format = [&](const std::string& partition) {
- if (erase_first && needs_erase(transport, partition.c_str())) {
- fb_queue_erase(partition);
- }
fb_perform_format(transport, partition, 0, type_override, size_override, "");
};
do_for_partitions(transport, partition.c_str(), slot_override, format, true);
@@ -1736,9 +1544,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());
}
@@ -1756,7 +1561,7 @@
std::string second_stage;
if (!args.empty()) second_stage = next_arg(&args);
- data = load_bootable_image(kernel, ramdisk, second_stage, &sz, cmdline, header_version);
+ data = load_bootable_image(kernel, ramdisk, second_stage, &sz);
fb_queue_download("boot.img", data, sz);
fb_queue_command("boot", "booting");
} else if (command == "flash") {
@@ -1771,9 +1576,6 @@
if (fname.empty()) die("cannot determine image filename for '%s'", pname.c_str());
auto flash = [&](const std::string &partition) {
- if (erase_first && needs_erase(transport, partition.c_str())) {
- fb_queue_erase(partition);
- }
do_flash(transport, partition.c_str(), fname.c_str());
};
do_for_partitions(transport, pname.c_str(), slot_override, flash, true);
@@ -1785,7 +1587,7 @@
std::string second_stage;
if (!args.empty()) second_stage = next_arg(&args);
- data = load_bootable_image(kernel, ramdisk, second_stage, &sz, cmdline, header_version);
+ data = load_bootable_image(kernel, ramdisk, second_stage, &sz);
auto flashraw = [&](const std::string& partition) {
fb_queue_flash(partition, data, sz);
};
@@ -1793,9 +1595,9 @@
} else if (command == "flashall") {
if (slot_override == "all") {
fprintf(stderr, "Warning: slot set to 'all'. Secondary slots will not be flashed.\n");
- do_flashall(transport, slot_override, erase_first, true);
+ do_flashall(transport, slot_override, true);
} else {
- do_flashall(transport, slot_override, erase_first, skip_secondary);
+ do_flashall(transport, slot_override, skip_secondary);
}
wants_reboot = true;
} else if (command == "update") {
@@ -1807,20 +1609,10 @@
if (!args.empty()) {
filename = next_arg(&args);
}
- do_update(transport, filename.c_str(), slot_override, erase_first,
- skip_secondary || slot_all);
+ do_update(transport, filename.c_str(), slot_override, skip_secondary || slot_all);
wants_reboot = true;
} else if (command == "set_active") {
std::string slot = verify_slot(transport, next_arg(&args), false);
-
- // Legacy support: verify_slot() removes leading underscores, we need to put them back
- // in for old bootloaders. Legacy bootloaders do not have the slot-count variable but
- // do have slot-suffixes.
- std::string var;
- if (!fb_getvar(transport, "slot-count", &var) &&
- fb_getvar(transport, "slot-suffixes", &var)) {
- slot = "_" + slot;
- }
fb_set_active(slot);
} else if (command == "stage") {
std::string filename = next_arg(&args);
@@ -1841,12 +1633,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());
}
@@ -1881,12 +1669,32 @@
} 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;
fprintf(stderr, "Finished. Total time: %.3fs\n", (now() - start));
return status;
}
+
+void FastBoot::ParseOsPatchLevel(boot_img_hdr_v1* hdr, const char* arg) {
+ unsigned year, month, day;
+ if (sscanf(arg, "%u-%u-%u", &year, &month, &day) != 3) {
+ syntax_error("OS patch level should be YYYY-MM-DD: %s", arg);
+ }
+ if (year < 2000 || year >= 2128) syntax_error("year out of range: %d", year);
+ if (month < 1 || month > 12) syntax_error("month out of range: %d", month);
+ hdr->SetOsPatchLevel(year, month);
+}
+
+void FastBoot::ParseOsVersion(boot_img_hdr_v1* hdr, const char* arg) {
+ unsigned major = 0, minor = 0, patch = 0;
+ std::vector<std::string> versions = android::base::Split(arg, ".");
+ if (versions.size() < 1 || versions.size() > 3 ||
+ (versions.size() >= 1 && !android::base::ParseUint(versions[0], &major)) ||
+ (versions.size() >= 2 && !android::base::ParseUint(versions[1], &minor)) ||
+ (versions.size() == 3 && !android::base::ParseUint(versions[2], &patch)) ||
+ (major > 0x7f || minor > 0x7f || patch > 0x7f)) {
+ syntax_error("bad OS version: %s", arg);
+ }
+ hdr->SetOsVersion(major, minor, patch);
+}
diff --git a/fastboot/fastboot.h b/fastboot/fastboot.h
index a31057a..2935eb5 100644
--- a/fastboot/fastboot.h
+++ b/fastboot/fastboot.h
@@ -26,16 +26,16 @@
* SUCH DAMAGE.
*/
-#ifndef _FASTBOOT_H_
-#define _FASTBOOT_H_
+#pragma once
#include <inttypes.h>
#include <stdlib.h>
#include <string>
-#include "transport.h"
+#include <bootimg.h>
+class Transport;
struct sparse_file;
/* protocol.c - fastboot protocol */
@@ -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,9 +91,16 @@
#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 */
extern char cur_product[FB_RESPONSE_SZ + 1];
-#endif
+class FastBoot {
+ public:
+ int Main(int argc, char* argv[]);
+
+ void ParseOsPatchLevel(boot_img_hdr_v1*, const char*);
+ void ParseOsVersion(boot_img_hdr_v1*, const char*);
+};
diff --git a/fastboot/fastboot_test.cpp b/fastboot/fastboot_test.cpp
new file mode 100644
index 0000000..1681427
--- /dev/null
+++ b/fastboot/fastboot_test.cpp
@@ -0,0 +1,61 @@
+/*
+ * 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 "fastboot.h"
+
+#include <gtest/gtest.h>
+
+TEST(FastBoot, ParseOsPatchLevel) {
+ FastBoot fb;
+ boot_img_hdr_v1 hdr;
+
+ hdr = {};
+ fb.ParseOsPatchLevel(&hdr, "2018-01-05");
+ ASSERT_EQ(2018U, 2000U + ((hdr.os_version >> 4) & 0x7f));
+ ASSERT_EQ(1U, ((hdr.os_version >> 0) & 0xf));
+
+ EXPECT_DEATH(fb.ParseOsPatchLevel(&hdr, "2018"), "should be YYYY-MM-DD");
+ EXPECT_DEATH(fb.ParseOsPatchLevel(&hdr, "2018-01"), "should be YYYY-MM-DD");
+ EXPECT_DEATH(fb.ParseOsPatchLevel(&hdr, "2128-01-05"), "year out of range");
+ EXPECT_DEATH(fb.ParseOsPatchLevel(&hdr, "2018-13-05"), "month out of range");
+}
+
+TEST(FastBoot, ParseOsVersion) {
+ FastBoot fb;
+ boot_img_hdr_v1 hdr;
+
+ hdr = {};
+ fb.ParseOsVersion(&hdr, "1.2.3");
+ ASSERT_EQ(1U, ((hdr.os_version >> 25) & 0x7f));
+ ASSERT_EQ(2U, ((hdr.os_version >> 18) & 0x7f));
+ ASSERT_EQ(3U, ((hdr.os_version >> 11) & 0x7f));
+
+ fb.ParseOsVersion(&hdr, "1.2");
+ ASSERT_EQ(1U, ((hdr.os_version >> 25) & 0x7f));
+ ASSERT_EQ(2U, ((hdr.os_version >> 18) & 0x7f));
+ ASSERT_EQ(0U, ((hdr.os_version >> 11) & 0x7f));
+
+ fb.ParseOsVersion(&hdr, "1");
+ ASSERT_EQ(1U, ((hdr.os_version >> 25) & 0x7f));
+ ASSERT_EQ(0U, ((hdr.os_version >> 18) & 0x7f));
+ ASSERT_EQ(0U, ((hdr.os_version >> 11) & 0x7f));
+
+ EXPECT_DEATH(fb.ParseOsVersion(&hdr, ""), "bad OS version");
+ EXPECT_DEATH(fb.ParseOsVersion(&hdr, "1.2.3.4"), "bad OS version");
+ EXPECT_DEATH(fb.ParseOsVersion(&hdr, "128.2.3"), "bad OS version");
+ EXPECT_DEATH(fb.ParseOsVersion(&hdr, "1.128.3"), "bad OS version");
+ EXPECT_DEATH(fb.ParseOsVersion(&hdr, "1.2.128"), "bad OS version");
+}
diff --git a/fastboot/fs.cpp b/fastboot/fs.cpp
index c30ca1e..6f51cf6 100644
--- a/fastboot/fs.cpp
+++ b/fastboot/fs.cpp
@@ -20,6 +20,7 @@
#include <android-base/errors.h>
#include <android-base/file.h>
+#include <android-base/macros.h>
#include <android-base/stringprintf.h>
#include <android-base/unique_fd.h>
diff --git a/fastboot/fs.h b/fastboot/fs.h
index c6baa7f..331100d 100644
--- a/fastboot/fs.h
+++ b/fastboot/fs.h
@@ -1,5 +1,4 @@
-#ifndef _FS_H_
-#define _FS_H_
+#pragma once
#include <string>
#include <stdint.h>
@@ -9,5 +8,3 @@
const struct fs_generator* fs_get_generator(const std::string& fs_type);
int fs_generator_generate(const struct fs_generator* gen, const char* fileName, long long partSize,
const std::string& initial_dir, unsigned eraseBlkSize = 0, unsigned logicalBlkSize = 0);
-
-#endif
diff --git a/fastboot/main.cpp b/fastboot/main.cpp
new file mode 100644
index 0000000..f1c8afb
--- /dev/null
+++ b/fastboot/main.cpp
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "fastboot.h"
+
+int main(int argc, char* argv[]) {
+ FastBoot fb;
+ return fb.Main(argc, argv);
+}
diff --git a/fastboot/protocol.cpp b/fastboot/protocol.cpp
index c239861..fda6f5d 100644
--- a/fastboot/protocol.cpp
+++ b/fastboot/protocol.cpp
@@ -57,10 +57,10 @@
}
static int64_t check_response(Transport* transport, uint32_t size, char* response) {
- char status[65];
+ char status[FB_RESPONSE_SZ + 1];
while (true) {
- int r = transport->Read(status, 64);
+ int r = transport->Read(status, FB_RESPONSE_SZ);
if (r < 0) {
g_error = android::base::StringPrintf("status read failed (%s)", strerror(errno));
transport->Close();
@@ -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;
@@ -115,7 +120,7 @@
static int64_t _command_start(Transport* transport, const std::string& cmd, uint32_t size,
char* response) {
- if (cmd.size() > 64) {
+ if (cmd.size() > FB_COMMAND_SZ) {
g_error = android::base::StringPrintf("command too large (%zu)", cmd.size());
return -1;
}
@@ -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));
@@ -267,19 +278,14 @@
return _command_end(transport);
}
-#define TRANSPORT_BUF_SIZE 1024
+static constexpr size_t TRANSPORT_BUF_SIZE = 1024;
static char transport_buf[TRANSPORT_BUF_SIZE];
-static int transport_buf_len;
+static size_t transport_buf_len;
-static int fb_download_data_sparse_write(void *priv, const void *data, int len)
-{
- int r;
- Transport* transport = reinterpret_cast<Transport*>(priv);
- int to_write;
- const char* ptr = reinterpret_cast<const char*>(data);
-
+static int fb_download_data_sparse_write(void* priv, const void* data, size_t len) {
+ const char* ptr = static_cast<const char*>(data);
if (transport_buf_len) {
- to_write = std::min(TRANSPORT_BUF_SIZE - transport_buf_len, len);
+ size_t to_write = std::min(TRANSPORT_BUF_SIZE - transport_buf_len, len);
memcpy(transport_buf + transport_buf_len, ptr, to_write);
transport_buf_len += to_write;
@@ -287,9 +293,10 @@
len -= to_write;
}
+ Transport* transport = static_cast<Transport*>(priv);
if (transport_buf_len == TRANSPORT_BUF_SIZE) {
- r = _command_write_data(transport, transport_buf, TRANSPORT_BUF_SIZE);
- if (r != TRANSPORT_BUF_SIZE) {
+ int64_t r = _command_write_data(transport, transport_buf, TRANSPORT_BUF_SIZE);
+ if (r != static_cast<int64_t>(TRANSPORT_BUF_SIZE)) {
return -1;
}
transport_buf_len = 0;
@@ -300,9 +307,9 @@
g_error = "internal error: transport_buf not empty";
return -1;
}
- to_write = round_down(len, TRANSPORT_BUF_SIZE);
- r = _command_write_data(transport, ptr, to_write);
- if (r != to_write) {
+ size_t to_write = round_down(len, TRANSPORT_BUF_SIZE);
+ int64_t r = _command_write_data(transport, ptr, to_write);
+ if (r != static_cast<int64_t>(to_write)) {
return -1;
}
ptr += to_write;
@@ -333,12 +340,12 @@
}
int fb_download_data_sparse(Transport* transport, struct sparse_file* s) {
- int size = sparse_file_len(s, true, false);
- if (size <= 0) {
+ int64_t size = sparse_file_len(s, true, false);
+ if (size <= 0 || size > std::numeric_limits<uint32_t>::max()) {
return -1;
}
- std::string cmd(android::base::StringPrintf("download:%08x", size));
+ std::string cmd(android::base::StringPrintf("download:%08" PRIx64, size));
int r = _command_start(transport, cmd, size, 0);
if (r < 0) {
return -1;
diff --git a/fastboot/socket.h b/fastboot/socket.h
index 7eaa0ab..e791f2c 100644
--- a/fastboot/socket.h
+++ b/fastboot/socket.h
@@ -30,8 +30,7 @@
// engine should not be using this interface directly, but instead should use a higher-level
// interface that enforces the fastboot protocol.
-#ifndef SOCKET_H_
-#define SOCKET_H_
+#pragma once
#include <functional>
#include <memory>
@@ -125,5 +124,3 @@
DISALLOW_COPY_AND_ASSIGN(Socket);
};
-
-#endif // SOCKET_H_
diff --git a/fastboot/socket_mock.h b/fastboot/socket_mock.h
index eacd6bb..6e95b16 100644
--- a/fastboot/socket_mock.h
+++ b/fastboot/socket_mock.h
@@ -26,8 +26,7 @@
* SUCH DAMAGE.
*/
-#ifndef SOCKET_MOCK_H_
-#define SOCKET_MOCK_H_
+#pragma once
#include <memory>
#include <queue>
@@ -97,5 +96,3 @@
DISALLOW_COPY_AND_ASSIGN(SocketMock);
};
-
-#endif // SOCKET_MOCK_H_
diff --git a/fastboot/tcp.h b/fastboot/tcp.h
index aa3ef13..8b638a4 100644
--- a/fastboot/tcp.h
+++ b/fastboot/tcp.h
@@ -26,8 +26,7 @@
* SUCH DAMAGE.
*/
-#ifndef TCP_H_
-#define TCP_H_
+#pragma once
#include <memory>
#include <string>
@@ -55,5 +54,3 @@
} // namespace internal
} // namespace tcp
-
-#endif // TCP_H_
diff --git a/fastboot/transport.h b/fastboot/transport.h
index 67d01f9..96b90d2 100644
--- a/fastboot/transport.h
+++ b/fastboot/transport.h
@@ -14,8 +14,7 @@
* limitations under the License.
*/
-#ifndef TRANSPORT_H_
-#define TRANSPORT_H_
+#pragma once
#include <android-base/macros.h>
@@ -44,5 +43,3 @@
private:
DISALLOW_COPY_AND_ASSIGN(Transport);
};
-
-#endif // TRANSPORT_H_
diff --git a/fastboot/udp.h b/fastboot/udp.h
index 14f5b35..8d37b84 100644
--- a/fastboot/udp.h
+++ b/fastboot/udp.h
@@ -26,8 +26,7 @@
* SUCH DAMAGE.
*/
-#ifndef UDP_H_
-#define UDP_H_
+#pragma once
#include <memory>
#include <string>
@@ -77,5 +76,3 @@
} // namespace internal
} // namespace udp
-
-#endif // UDP_H_
diff --git a/fastboot/usb.h b/fastboot/usb.h
index 4acf12d..5b44468 100644
--- a/fastboot/usb.h
+++ b/fastboot/usb.h
@@ -26,8 +26,7 @@
* SUCH DAMAGE.
*/
-#ifndef _USB_H_
-#define _USB_H_
+#pragma once
#include "transport.h"
@@ -56,5 +55,3 @@
typedef int (*ifc_match_func)(usb_ifc_info *ifc);
Transport* usb_open(ifc_match_func callback);
-
-#endif
diff --git a/fastboot/usbtest.cpp b/fastboot/usbtest.cpp
deleted file mode 100644
index 9423c6d..0000000
--- a/fastboot/usbtest.cpp
+++ /dev/null
@@ -1,212 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
- * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
- * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
- * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
- * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
- * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
- * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <errno.h>
-
-#include <sys/time.h>
-
-#include "usb.h"
-
-static unsigned arg_size = 4096;
-static unsigned arg_count = 4096;
-
-long long NOW(void)
-{
- struct timeval tv;
- gettimeofday(&tv, 0);
-
- return (((long long) tv.tv_sec) * ((long long) 1000000)) +
- (((long long) tv.tv_usec));
-}
-
-int printifc(usb_ifc_info *info)
-{
- printf("dev: csp=%02x/%02x/%02x v=%04x p=%04x ",
- info->dev_class, info->dev_subclass, info->dev_protocol,
- info->dev_vendor, info->dev_product);
- printf("ifc: csp=%02x/%02x/%02x%s%s\n",
- info->ifc_class, info->ifc_subclass, info->ifc_protocol,
- info->has_bulk_in ? " in" : "",
- info->has_bulk_out ? " out" : "");
- return -1;
-}
-
-int match_null(usb_ifc_info *info)
-{
- if(info->dev_vendor != 0x18d1) return -1;
- if(info->ifc_class != 0xff) return -1;
- if(info->ifc_subclass != 0xfe) return -1;
- if(info->ifc_protocol != 0x01) return -1;
- return 0;
-}
-
-int match_zero(usb_ifc_info *info)
-{
- if(info->dev_vendor != 0x18d1) return -1;
- if(info->ifc_class != 0xff) return -1;
- if(info->ifc_subclass != 0xfe) return -1;
- if(info->ifc_protocol != 0x02) return -1;
- return 0;
-}
-
-int match_loop(usb_ifc_info *info)
-{
- if(info->dev_vendor != 0x18d1) return -1;
- if(info->ifc_class != 0xff) return -1;
- if(info->ifc_subclass != 0xfe) return -1;
- if(info->ifc_protocol != 0x03) return -1;
- return 0;
-}
-
-int test_null(Transport* usb)
-{
- unsigned i;
- unsigned char buf[4096];
- memset(buf, 0xee, 4096);
- long long t0, t1;
-
- t0 = NOW();
- for (i = 0; i < arg_count; i++) {
- if (usb->Write(buf, arg_size) != static_cast<int>(arg_size)) {
- fprintf(stderr,"write failed (%s)\n", strerror(errno));
- return -1;
- }
- }
- t1 = NOW();
- fprintf(stderr,"%d bytes in %lld uS\n", arg_count * arg_size, (t1 - t0));
- return 0;
-}
-
-int test_zero(Transport* usb)
-{
- unsigned i;
- unsigned char buf[4096];
- long long t0, t1;
-
- t0 = NOW();
- for (i = 0; i < arg_count; i++) {
- if (usb->Read(buf, arg_size) != static_cast<int>(arg_size)) {
- fprintf(stderr,"read failed (%s)\n", strerror(errno));
- return -1;
- }
- }
- t1 = NOW();
- fprintf(stderr,"%d bytes in %lld uS\n", arg_count * arg_size, (t1 - t0));
- return 0;
-}
-
-struct
-{
- const char *cmd;
- ifc_match_func match;
- int (*test)(Transport* usb);
- const char *help;
-} tests[] = {
- { "list", printifc, NULL, "list interfaces" },
- { "send", match_null, test_null, "send to null interface" },
- { "recv", match_zero, test_zero, "recv from zero interface" },
- { "loop", match_loop, NULL, "exercise loopback interface" },
- { NULL, NULL, NULL, NULL },
-};
-
-int usage(void)
-{
- int i;
-
- fprintf(stderr,"usage: usbtest <testname>\n\navailable tests:\n");
- for(i = 0; tests[i].cmd; i++) {
- fprintf(stderr," %-8s %s\n", tests[i].cmd, tests[i].help);
- }
- return -1;
-}
-
-int process_args(int argc, char **argv)
-{
- while(argc-- > 0) {
- char *arg = *argv++;
- if(!strncmp(arg,"count=",6)) {
- arg_count = atoi(arg + 6);
- } else if(!strncmp(arg,"size=",5)) {
- arg_size = atoi(arg + 5);
- } else {
- fprintf(stderr,"unknown argument: %s\n", arg);
- return -1;
- }
- }
-
- if(arg_count == 0) {
- fprintf(stderr,"count may not be zero\n");
- return -1;
- }
-
- if(arg_size > 4096) {
- fprintf(stderr,"size may not be greater than 4096\n");
- return -1;
- }
-
- return 0;
-}
-
-int main(int argc, char **argv)
-{
- Transport* usb;
- int i;
-
- if(argc < 2)
- return usage();
-
- if(argc > 2) {
- if(process_args(argc - 2, argv + 2))
- return -1;
- }
-
- for(i = 0; tests[i].cmd; i++) {
- if(!strcmp(argv[1], tests[i].cmd)) {
- usb = usb_open(tests[i].match);
- if(tests[i].test) {
- if(usb == 0) {
- fprintf(stderr,"usbtest: %s: could not find interface\n",
- tests[i].cmd);
- return -1;
- }
- if(tests[i].test(usb)) {
- fprintf(stderr,"usbtest: %s: FAIL\n", tests[i].cmd);
- return -1;
- } else {
- fprintf(stderr,"usbtest: %s: OKAY\n", tests[i].cmd);
- }
- }
- return 0;
- }
- }
-
- return usage();
-}
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/Android.bp b/fs_mgr/Android.bp
index f23150d..05dba15 100644
--- a/fs_mgr/Android.bp
+++ b/fs_mgr/Android.bp
@@ -42,6 +42,7 @@
"fs_mgr_verity.cpp",
"fs_mgr_avb.cpp",
"fs_mgr_avb_ops.cpp",
+ "fs_mgr_dm_linear.cpp",
],
static_libs: [
"libfec",
diff --git a/fs_mgr/fs_mgr.cpp b/fs_mgr/fs_mgr.cpp
index 9aab0ba..6e9ffba 100644
--- a/fs_mgr/fs_mgr.cpp
+++ b/fs_mgr/fs_mgr.cpp
@@ -794,6 +794,29 @@
return true;
}
+bool fs_mgr_update_logical_partition(struct fstab_rec* rec) {
+ // Logical partitions are specified with a named partition rather than a
+ // block device, so if the block device is a path, then it has already
+ // been updated.
+ if (rec->blk_device[0] == '/') {
+ return true;
+ }
+
+ android::base::unique_fd dm_fd(open("/dev/device-mapper", O_RDONLY));
+ if (dm_fd < 0) {
+ PLOG(ERROR) << "open /dev/device-mapper failed";
+ return false;
+ }
+ struct dm_ioctl io;
+ std::string device_name;
+ if (!fs_mgr_dm_get_device_name(&io, rec->blk_device, dm_fd, &device_name)) {
+ return false;
+ }
+ free(rec->blk_device);
+ rec->blk_device = strdup(device_name.c_str());
+ return true;
+}
+
/* When multiple fstab records share the same mount_point, it will
* try to mount each one in turn, and ignore any duplicates after a
* first successful mount.
@@ -845,6 +868,13 @@
}
}
+ if ((fstab->recs[i].fs_mgr_flags & MF_LOGICAL)) {
+ if (!fs_mgr_update_logical_partition(&fstab->recs[i])) {
+ LERROR << "Could not set up logical partition, skipping!";
+ continue;
+ }
+ }
+
if (fstab->recs[i].fs_mgr_flags & MF_WAIT &&
!fs_mgr_wait_for_file(fstab->recs[i].blk_device, 20s)) {
LERROR << "Skipping '" << fstab->recs[i].blk_device << "' during mount_all";
@@ -1065,6 +1095,13 @@
return FS_MGR_DOMNT_FAILED;
}
+ if ((fstab->recs[i].fs_mgr_flags & MF_LOGICAL)) {
+ if (!fs_mgr_update_logical_partition(&fstab->recs[i])) {
+ LERROR << "Could not set up logical partition, skipping!";
+ continue;
+ }
+ }
+
/* First check the filesystem if requested */
if (fstab->recs[i].fs_mgr_flags & MF_WAIT && !fs_mgr_wait_for_file(n_blk_device, 20s)) {
LERROR << "Skipping mounting '" << n_blk_device << "'";
@@ -1383,7 +1420,7 @@
mount_point = basename(fstab->recs[i].mount_point);
}
- fs_mgr_verity_ioctl_init(io, mount_point, 0);
+ fs_mgr_dm_ioctl_init(io, DM_BUF_SIZE, mount_point);
const char* status;
if (ioctl(fd, DM_TABLE_STATUS, io)) {
diff --git a/fs_mgr/fs_mgr_avb.cpp b/fs_mgr/fs_mgr_avb.cpp
index 7824cfa..5a9cb65 100644
--- a/fs_mgr/fs_mgr_avb.cpp
+++ b/fs_mgr/fs_mgr_avb.cpp
@@ -303,13 +303,14 @@
static bool load_verity_table(struct dm_ioctl* io, const std::string& dm_device_name, int fd,
uint64_t image_size, const std::string& verity_table) {
- fs_mgr_verity_ioctl_init(io, dm_device_name, DM_STATUS_TABLE_FLAG);
+ fs_mgr_dm_ioctl_init(io, DM_BUF_SIZE, dm_device_name);
// The buffer consists of [dm_ioctl][dm_target_spec][verity_params].
char* buffer = (char*)io;
// Builds the dm_target_spec arguments.
struct dm_target_spec* dm_target = (struct dm_target_spec*)&buffer[sizeof(struct dm_ioctl)];
+ io->flags = DM_READONLY_FLAG;
io->target_count = 1;
dm_target->status = 0;
dm_target->sector_start = 0;
@@ -359,14 +360,14 @@
alignas(dm_ioctl) char buffer[DM_BUF_SIZE];
struct dm_ioctl* io = (struct dm_ioctl*)buffer;
const std::string mount_point(basename(fstab_entry->mount_point));
- if (!fs_mgr_create_verity_device(io, mount_point, fd)) {
+ if (!fs_mgr_dm_create_device(io, mount_point, fd)) {
LERROR << "Couldn't create verity device!";
return false;
}
// Gets the name of the device file.
std::string verity_blk_name;
- if (!fs_mgr_get_verity_device_name(io, mount_point, fd, &verity_blk_name)) {
+ if (!fs_mgr_dm_get_device_name(io, mount_point, fd, &verity_blk_name)) {
LERROR << "Couldn't get verity device number!";
return false;
}
@@ -385,7 +386,7 @@
}
// Activates the device.
- if (!fs_mgr_resume_verity_table(io, mount_point, fd)) {
+ if (!fs_mgr_dm_resume_table(io, mount_point, fd)) {
return false;
}
@@ -584,7 +585,13 @@
// Derives partition_name from blk_device to query the corresponding AVB HASHTREE descriptor
// to setup dm-verity. The partition_names in AVB descriptors are without A/B suffix.
- std::string partition_name(basename(fstab_entry->blk_device));
+ std::string partition_name;
+ if (fstab_entry->fs_mgr_flags & MF_LOGICAL) {
+ partition_name = fstab_entry->logical_partition_name;
+ } else {
+ partition_name = basename(fstab_entry->blk_device);
+ }
+
if (fstab_entry->fs_mgr_flags & MF_SLOTSELECT) {
auto ab_suffix = partition_name.rfind(fs_mgr_get_slot_suffix());
if (ab_suffix != std::string::npos) {
diff --git a/fs_mgr/fs_mgr_dm_ioctl.cpp b/fs_mgr/fs_mgr_dm_ioctl.cpp
index 4cbd5a8..3a7fae4 100644
--- a/fs_mgr/fs_mgr_dm_ioctl.cpp
+++ b/fs_mgr/fs_mgr_dm_ioctl.cpp
@@ -23,21 +23,20 @@
#include "fs_mgr_priv.h"
#include "fs_mgr_priv_dm_ioctl.h"
-void fs_mgr_verity_ioctl_init(struct dm_ioctl* io, const std::string& name, unsigned flags) {
- memset(io, 0, DM_BUF_SIZE);
- io->data_size = DM_BUF_SIZE;
+void fs_mgr_dm_ioctl_init(struct dm_ioctl* io, size_t size, const std::string& name) {
+ memset(io, 0, size);
+ io->data_size = size;
io->data_start = sizeof(struct dm_ioctl);
io->version[0] = 4;
io->version[1] = 0;
io->version[2] = 0;
- io->flags = flags | DM_READONLY_FLAG;
if (!name.empty()) {
strlcpy(io->name, name.c_str(), sizeof(io->name));
}
}
-bool fs_mgr_create_verity_device(struct dm_ioctl* io, const std::string& name, int fd) {
- fs_mgr_verity_ioctl_init(io, name, 1);
+bool fs_mgr_dm_create_device(struct dm_ioctl* io, const std::string& name, int fd) {
+ fs_mgr_dm_ioctl_init(io, sizeof(*io), name);
if (ioctl(fd, DM_DEV_CREATE, io)) {
PERROR << "Error creating device mapping";
return false;
@@ -45,8 +44,8 @@
return true;
}
-bool fs_mgr_destroy_verity_device(struct dm_ioctl* io, const std::string& name, int fd) {
- fs_mgr_verity_ioctl_init(io, name, 0);
+bool fs_mgr_dm_destroy_device(struct dm_ioctl* io, const std::string& name, int fd) {
+ fs_mgr_dm_ioctl_init(io, sizeof(*io), name);
if (ioctl(fd, DM_DEV_REMOVE, io)) {
PERROR << "Error removing device mapping";
return false;
@@ -54,13 +53,13 @@
return true;
}
-bool fs_mgr_get_verity_device_name(struct dm_ioctl* io, const std::string& name, int fd,
- std::string* out_dev_name) {
+bool fs_mgr_dm_get_device_name(struct dm_ioctl* io, const std::string& name, int fd,
+ std::string* out_dev_name) {
FS_MGR_CHECK(out_dev_name != nullptr);
- fs_mgr_verity_ioctl_init(io, name, 0);
+ fs_mgr_dm_ioctl_init(io, sizeof(*io), name);
if (ioctl(fd, DM_DEV_STATUS, io)) {
- PERROR << "Error fetching verity device number";
+ PERROR << "Error fetching device-mapper device number";
return false;
}
@@ -70,10 +69,10 @@
return true;
}
-bool fs_mgr_resume_verity_table(struct dm_ioctl* io, const std::string& name, int fd) {
- fs_mgr_verity_ioctl_init(io, name, 0);
+bool fs_mgr_dm_resume_table(struct dm_ioctl* io, const std::string& name, int fd) {
+ fs_mgr_dm_ioctl_init(io, sizeof(*io), name);
if (ioctl(fd, DM_DEV_SUSPEND, io)) {
- PERROR << "Error activating verity device";
+ PERROR << "Error activating device table";
return false;
}
return true;
diff --git a/fs_mgr/fs_mgr_dm_linear.cpp b/fs_mgr/fs_mgr_dm_linear.cpp
new file mode 100644
index 0000000..b2f3a68
--- /dev/null
+++ b/fs_mgr/fs_mgr_dm_linear.cpp
@@ -0,0 +1,141 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "fs_mgr_dm_linear.h"
+
+#include <inttypes.h>
+#include <linux/dm-ioctl.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#include <sstream>
+
+#include <android-base/logging.h>
+#include <android-base/stringprintf.h>
+#include <android-base/strings.h>
+#include <android-base/unique_fd.h>
+
+#include "fs_mgr_priv.h"
+#include "fs_mgr_priv_dm_ioctl.h"
+
+namespace android {
+namespace fs_mgr {
+
+std::string LogicalPartitionExtent::Serialize() const {
+ // Note: we need to include an explicit null-terminator.
+ std::string argv =
+ android::base::StringPrintf("%s %" PRIu64, block_device_.c_str(), first_sector_);
+ argv.push_back(0);
+
+ // The kernel expects each target to be aligned.
+ size_t spec_bytes = sizeof(struct dm_target_spec) + argv.size();
+ size_t padding = ((spec_bytes + 7) & ~7) - spec_bytes;
+ for (size_t i = 0; i < padding; i++) {
+ argv.push_back(0);
+ }
+
+ struct dm_target_spec spec;
+ spec.sector_start = logical_sector_;
+ spec.length = num_sectors_;
+ spec.status = 0;
+ strcpy(spec.target_type, "linear");
+ spec.next = sizeof(struct dm_target_spec) + argv.size();
+
+ return std::string((char*)&spec, sizeof(spec)) + argv;
+}
+
+static bool LoadDmTable(int dm_fd, const LogicalPartition& partition) {
+ // Combine all dm_target_spec buffers together.
+ std::string target_string;
+ for (const auto& extent : partition.extents) {
+ target_string += extent.Serialize();
+ }
+
+ // Allocate the ioctl buffer.
+ size_t buffer_size = sizeof(struct dm_ioctl) + target_string.size();
+ std::unique_ptr<uint8_t[]> buffer = std::make_unique<uint8_t[]>(buffer_size);
+
+ // Initialize the ioctl buffer header, then copy our target specs in.
+ struct dm_ioctl* io = reinterpret_cast<struct dm_ioctl*>(buffer.get());
+ fs_mgr_dm_ioctl_init(io, buffer_size, partition.name);
+ io->target_count = partition.extents.size();
+ if (partition.attributes & kPartitionReadonly) {
+ io->flags |= DM_READONLY_FLAG;
+ }
+ memcpy(io + 1, target_string.c_str(), target_string.size());
+
+ if (ioctl(dm_fd, DM_TABLE_LOAD, io)) {
+ PERROR << "Failed ioctl() on DM_TABLE_LOAD, partition " << partition.name;
+ return false;
+ }
+ return true;
+}
+
+static bool LoadTablesAndActivate(int dm_fd, const LogicalPartition& partition) {
+ if (!LoadDmTable(dm_fd, partition)) {
+ return false;
+ }
+
+ struct dm_ioctl io;
+ return fs_mgr_dm_resume_table(&io, partition.name, dm_fd);
+}
+
+static bool CreateDmDeviceForPartition(int dm_fd, const LogicalPartition& partition) {
+ struct dm_ioctl io;
+ if (!fs_mgr_dm_create_device(&io, partition.name, dm_fd)) {
+ return false;
+ }
+ if (!LoadTablesAndActivate(dm_fd, partition)) {
+ // Remove the device rather than leave it in an inactive state.
+ fs_mgr_dm_destroy_device(&io, partition.name, dm_fd);
+ return false;
+ }
+
+ LINFO << "Created device-mapper device: " << partition.name;
+ return true;
+}
+
+bool CreateLogicalPartitions(const LogicalPartitionTable& table) {
+ android::base::unique_fd dm_fd(open("/dev/device-mapper", O_RDWR));
+ if (dm_fd < 0) {
+ PLOG(ERROR) << "failed to open /dev/device-mapper";
+ return false;
+ }
+ for (const auto& partition : table.partitions) {
+ if (!CreateDmDeviceForPartition(dm_fd, partition)) {
+ LOG(ERROR) << "could not create dm-linear device for partition: " << partition.name;
+ return false;
+ }
+ }
+ return true;
+}
+
+std::unique_ptr<LogicalPartitionTable> LoadPartitionsFromDeviceTree() {
+ return nullptr;
+}
+
+} // namespace fs_mgr
+} // namespace android
diff --git a/fs_mgr/fs_mgr_fstab.cpp b/fs_mgr/fs_mgr_fstab.cpp
index 68cc530..af4d6c1 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 {
@@ -107,6 +109,7 @@
{"logicalblk=", MF_LOGICALBLKSIZE},
{"sysfs_path=", MF_SYSFS},
{"defaults", 0},
+ {"logical", MF_LOGICAL},
{0, 0},
};
@@ -625,6 +628,10 @@
fstab->recs[cnt].erase_blk_size = flag_vals.erase_blk_size;
fstab->recs[cnt].logical_blk_size = flag_vals.logical_blk_size;
fstab->recs[cnt].sysfs_path = flag_vals.sysfs_path;
+ if (fstab->recs[cnt].fs_mgr_flags & MF_LOGICAL) {
+ fstab->recs[cnt].logical_partition_name = strdup(fstab->recs[cnt].blk_device);
+ }
+
cnt++;
}
/* If an A/B partition, modify block device to be the real block device */
@@ -834,6 +841,7 @@
for (i = 0; i < fstab->num_entries; i++) {
/* Free the pointers return by strdup(3) */
free(fstab->recs[i].blk_device);
+ free(fstab->recs[i].logical_partition_name);
free(fstab->recs[i].mount_point);
free(fstab->recs[i].fs_type);
free(fstab->recs[i].fs_options);
@@ -998,3 +1006,7 @@
{
return fstab->fs_mgr_flags & MF_SYSFS;
}
+
+int fs_mgr_is_logical(const struct fstab_rec* fstab) {
+ return fstab->fs_mgr_flags & MF_LOGICAL;
+}
diff --git a/fs_mgr/fs_mgr_priv.h b/fs_mgr/fs_mgr_priv.h
index 9011bb3..a347faf 100644
--- a/fs_mgr/fs_mgr_priv.h
+++ b/fs_mgr/fs_mgr_priv.h
@@ -82,6 +82,7 @@
*
*/
+// clang-format off
#define MF_WAIT 0x1
#define MF_CHECK 0x2
#define MF_CRYPT 0x4
@@ -111,6 +112,8 @@
#define MF_AVB 0X2000000
#define MF_KEYDIRECTORY 0X4000000
#define MF_SYSFS 0X8000000
+#define MF_LOGICAL 0x10000000
+// clang-format on
#define DM_BUF_SIZE 4096
diff --git a/fs_mgr/fs_mgr_priv_dm_ioctl.h b/fs_mgr/fs_mgr_priv_dm_ioctl.h
index a00a9c1..792475d 100644
--- a/fs_mgr/fs_mgr_priv_dm_ioctl.h
+++ b/fs_mgr/fs_mgr_priv_dm_ioctl.h
@@ -20,15 +20,15 @@
#include <linux/dm-ioctl.h>
#include <string>
-void fs_mgr_verity_ioctl_init(struct dm_ioctl* io, const std::string& name, unsigned flags);
+void fs_mgr_dm_ioctl_init(struct dm_ioctl* io, size_t size, const std::string& name);
-bool fs_mgr_create_verity_device(struct dm_ioctl* io, const std::string& name, int fd);
+bool fs_mgr_dm_create_device(struct dm_ioctl* io, const std::string& name, int fd);
-bool fs_mgr_destroy_verity_device(struct dm_ioctl* io, const std::string& name, int fd);
+bool fs_mgr_dm_destroy_device(struct dm_ioctl* io, const std::string& name, int fd);
-bool fs_mgr_get_verity_device_name(struct dm_ioctl* io, const std::string& name, int fd,
- std::string* out_dev_name);
+bool fs_mgr_dm_get_device_name(struct dm_ioctl* io, const std::string& name, int fd,
+ std::string* out_dev_name);
-bool fs_mgr_resume_verity_table(struct dm_ioctl* io, const std::string& name, int fd);
+bool fs_mgr_dm_resume_table(struct dm_ioctl* io, const std::string& name, int fd);
#endif /* __CORE_FS_MGR_PRIV_DM_IOCTL_H */
diff --git a/fs_mgr/fs_mgr_slotselect.cpp b/fs_mgr/fs_mgr_slotselect.cpp
index 0a113b4..3b01d0e 100644
--- a/fs_mgr/fs_mgr_slotselect.cpp
+++ b/fs_mgr/fs_mgr_slotselect.cpp
@@ -36,19 +36,30 @@
std::string ab_suffix;
for (n = 0; n < fstab->num_entries; n++) {
- if (fstab->recs[n].fs_mgr_flags & MF_SLOTSELECT) {
- char *tmp;
+ fstab_rec& record = fstab->recs[n];
+ if (record.fs_mgr_flags & MF_SLOTSELECT) {
if (ab_suffix.empty()) {
ab_suffix = fs_mgr_get_slot_suffix();
// Return false if failed to get ab_suffix when MF_SLOTSELECT is specified.
if (ab_suffix.empty()) return false;
}
- if (asprintf(&tmp, "%s%s", fstab->recs[n].blk_device, ab_suffix.c_str()) > 0) {
- free(fstab->recs[n].blk_device);
- fstab->recs[n].blk_device = tmp;
- } else {
+
+ char* new_blk_device;
+ if (asprintf(&new_blk_device, "%s%s", record.blk_device, ab_suffix.c_str()) <= 0) {
return false;
}
+ free(record.blk_device);
+ record.blk_device = new_blk_device;
+
+ char* new_partition_name;
+ if (record.logical_partition_name) {
+ if (asprintf(&new_partition_name, "%s%s", record.logical_partition_name,
+ ab_suffix.c_str()) <= 0) {
+ return false;
+ }
+ free(record.logical_partition_name);
+ record.logical_partition_name = new_partition_name;
+ }
}
}
return true;
diff --git a/fs_mgr/fs_mgr_verity.cpp b/fs_mgr/fs_mgr_verity.cpp
index 896b603..fe41f8a 100644
--- a/fs_mgr/fs_mgr_verity.cpp
+++ b/fs_mgr/fs_mgr_verity.cpp
@@ -258,12 +258,13 @@
char *buffer = (char*) io;
size_t bufsize;
- fs_mgr_verity_ioctl_init(io, name, DM_STATUS_TABLE_FLAG);
+ fs_mgr_dm_ioctl_init(io, DM_BUF_SIZE, name);
struct dm_target_spec *tgt = (struct dm_target_spec *) &buffer[sizeof(struct dm_ioctl)];
// set tgt arguments
io->target_count = 1;
+ io->flags = DM_READONLY_FLAG;
tgt->status = 0;
tgt->sector_start = 0;
tgt->length = device_size / 512;
@@ -804,13 +805,13 @@
}
// create the device
- if (!fs_mgr_create_verity_device(io, mount_point, fd)) {
+ if (!fs_mgr_dm_create_device(io, mount_point, fd)) {
LERROR << "Couldn't create verity device!";
goto out;
}
// get the name of the device file
- if (!fs_mgr_get_verity_device_name(io, mount_point, fd, &verity_blk_name)) {
+ if (!fs_mgr_dm_get_device_name(io, mount_point, fd, &verity_blk_name)) {
LERROR << "Couldn't get verity device number!";
goto out;
}
@@ -899,7 +900,7 @@
loaded:
// activate the device
- if (!fs_mgr_resume_verity_table(io, mount_point, fd)) {
+ if (!fs_mgr_dm_resume_table(io, mount_point, fd)) {
goto out;
}
@@ -922,7 +923,7 @@
if (!verified_at_boot) {
free(fstab->blk_device);
fstab->blk_device = strdup(verity_blk_name.c_str());
- } else if (!fs_mgr_destroy_verity_device(io, mount_point, fd)) {
+ } else if (!fs_mgr_dm_destroy_device(io, mount_point, fd)) {
LERROR << "Failed to remove verity device " << mount_point.c_str();
goto out;
}
diff --git a/fs_mgr/include/fs_mgr.h b/fs_mgr/include/fs_mgr.h
index 653d8fa..72f019e 100644
--- a/fs_mgr/include/fs_mgr.h
+++ b/fs_mgr/include/fs_mgr.h
@@ -76,6 +76,7 @@
bool fs_mgr_load_verity_state(int* mode);
bool fs_mgr_update_verity_state(fs_mgr_verity_state_callback callback);
int fs_mgr_swapon_all(struct fstab *fstab);
+bool fs_mgr_update_logical_partition(struct fstab_rec* rec);
int fs_mgr_do_format(struct fstab_rec *fstab, bool reserve_footer);
diff --git a/fs_mgr/include/fs_mgr_dm_linear.h b/fs_mgr/include/fs_mgr_dm_linear.h
new file mode 100644
index 0000000..7f928e5
--- /dev/null
+++ b/fs_mgr/include/fs_mgr_dm_linear.h
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef __CORE_FS_MGR_DM_LINEAR_H
+#define __CORE_FS_MGR_DM_LINEAR_H
+
+#include <stdint.h>
+#include <memory>
+#include <string>
+#include <vector>
+
+namespace android {
+namespace fs_mgr {
+
+static const uint32_t kPartitionReadonly = 0x1;
+
+class LogicalPartitionExtent {
+ public:
+ LogicalPartitionExtent() : logical_sector_(0), first_sector_(0), num_sectors_(0) {}
+ LogicalPartitionExtent(uint64_t logical_sector, uint64_t first_sector, uint64_t num_sectors,
+ const std::string& block_device)
+ : logical_sector_(logical_sector),
+ first_sector_(first_sector),
+ num_sectors_(num_sectors),
+ block_device_(block_device) {}
+
+ // Return a string containing the dm_target_spec buffer needed to use this
+ // extent in a device-mapper table.
+ std::string Serialize() const;
+
+ const std::string& block_device() const { return block_device_; }
+
+ private:
+ // Logical sector this extent represents in the presented block device.
+ // This is equal to the previous extent's logical sector plus the number
+ // of sectors in that extent. The first extent always starts at 0.
+ uint64_t logical_sector_;
+ // First 512-byte sector of this extent, on the source block device.
+ uint64_t first_sector_;
+ // Number of 512-byte sectors.
+ uint64_t num_sectors_;
+ // Target block device.
+ std::string block_device_;
+};
+
+struct LogicalPartition {
+ LogicalPartition() : attributes(0), num_sectors(0) {}
+
+ std::string name;
+ uint32_t attributes;
+ // Number of 512-byte sectors total.
+ uint64_t num_sectors;
+ // List of extents.
+ std::vector<LogicalPartitionExtent> extents;
+};
+
+struct LogicalPartitionTable {
+ // List of partitions in the partition table.
+ std::vector<LogicalPartition> partitions;
+};
+
+// Load a dm-linear table from the device tree if one is available; otherwise,
+// return null.
+std::unique_ptr<LogicalPartitionTable> LoadPartitionsFromDeviceTree();
+
+// Create device-mapper devices for the given partition table.
+//
+// On success, two devices nodes will be created for each partition, both
+// pointing to the same device:
+// /dev/block/dm-<N> where N is a sequential ID assigned by device-mapper.
+// /dev/block/dm-<name> where |name| is the partition name.
+//
+bool CreateLogicalPartitions(const LogicalPartitionTable& table);
+
+} // namespace fs_mgr
+} // namespace android
+
+#endif // __CORE_FS_MGR_DM_LINEAR_H
diff --git a/fs_mgr/include_fstab/fstab/fstab.h b/fs_mgr/include_fstab/fstab/fstab.h
index e8da2ac..d232cca 100644
--- a/fs_mgr/include_fstab/fstab/fstab.h
+++ b/fs_mgr/include_fstab/fstab/fstab.h
@@ -38,6 +38,7 @@
struct fstab_rec {
char* blk_device;
+ char* logical_partition_name;
char* mount_point;
char* fs_type;
unsigned long flags;
@@ -85,6 +86,7 @@
int fs_mgr_is_nofail(const struct fstab_rec* fstab);
int fs_mgr_is_latemount(const struct fstab_rec* fstab);
int fs_mgr_is_quota(const struct fstab_rec* fstab);
+int fs_mgr_is_logical(const struct fstab_rec* fstab);
int fs_mgr_has_sysfs_path(const struct fstab_rec* fstab);
std::string fs_mgr_get_slot_suffix();
diff --git a/healthd/Android.mk b/healthd/Android.mk
index 818488d..86f7cf0 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/healthd/OWNERS b/healthd/OWNERS
index 2375f7c..00df08a 100644
--- a/healthd/OWNERS
+++ b/healthd/OWNERS
@@ -1 +1,2 @@
+elsk@google.com
toddpoynor@google.com
diff --git a/init/Android.bp b/init/Android.bp
index 70a4ac6..a31c5a5 100644
--- a/init/Android.bp
+++ b/init/Android.bp
@@ -180,6 +180,7 @@
"util_test.cpp",
],
static_libs: ["libinit"],
+ test_suites: ["device-tests"],
}
cc_benchmark {
diff --git a/init/README.md b/init/README.md
index 5c2352b..550ef05 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
@@ -174,11 +193,103 @@
`disabled`
> This service will not automatically start with its class.
- It must be explicitly started by name.
+ It must be explicitly started by name or by interface name.
+
+`enter_namespace <type> <path>`
+> Enters the namespace of type _type_ located at _path_. Only network namespaces are supported with
+ _type_ set to "net". Note that only one namespace of a given _type_ may be entered.
+
+`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.
+
+`sigstop`
+> Send SIGSTOP to the service immediately before exec is called. This is intended for debugging.
+ See the below section on debugging for how this can be used.
+
`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 +298,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 +314,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
--------
@@ -686,23 +716,39 @@
Debugging init
--------------
-By default, programs executed by init will drop stdout and stderr into
-/dev/null. To help with debugging, you can execute your program via the
-Android program logwrapper. This will redirect stdout/stderr into the
-Android logging system (accessed via logcat).
+Launching init services without init is not recommended as init sets up a significant amount of
+environment (user, groups, security label, capabilities, etc) that is hard to replicate manually.
-For example
-service akmd /system/bin/logwrapper /sbin/akmd
+If it is required to debug a service from its very start, the `sigstop` service option is added.
+This option will send SIGSTOP to a service immediately before calling exec. This gives a window
+where developers can attach a debugger, strace, etc before continuing the service with SIGCONT.
-For quicker turnaround when working on init itself, use:
+This flag can also be dynamically controled via the ctl.sigstop_on and ctl.sigstop_off properties.
- mm -j &&
- m ramdisk-nodeps &&
- m bootimage-nodeps &&
- adb reboot bootloader &&
- fastboot boot $ANDROID_PRODUCT_OUT/boot.img
+Below is an example of dynamically debugging logd via the above:
-Alternatively, use the emulator:
+ stop logd
+ setprop ctl.sigstop_on logd
+ start logd
+ ps -e | grep logd
+ > logd 4343 1 18156 1684 do_signal_stop 538280 T init
+ gdbclient.py -p 4343
+ b main
+ c
+ c
+ c
+ > Breakpoint 1, main (argc=1, argv=0x7ff8c9a488) at system/core/logd/main.cpp:427
- emulator -partition-size 1024 \
- -verbose -show-kernel -no-window
+Below is an example of doing the same but with strace
+
+ stop logd
+ setprop ctl.sigstop_on logd
+ start logd
+ ps -e | grep logd
+ > logd 4343 1 18156 1684 do_signal_stop 538280 T init
+ strace -p 4343
+
+ (From a different shell)
+ kill -SIGCONT 4343
+
+ > strace runs
diff --git a/init/bootchart.cpp b/init/bootchart.cpp
index 379b4fa..c2cf573 100644
--- a/init/bootchart.cpp
+++ b/init/bootchart.cpp
@@ -32,12 +32,14 @@
#include <mutex>
#include <thread>
+#include <android-base/chrono_utils.h>
#include <android-base/file.h>
#include <android-base/logging.h>
#include <android-base/properties.h>
#include <android-base/stringprintf.h>
using android::base::StringPrintf;
+using android::base::boot_clock;
using namespace std::chrono_literals;
namespace android {
@@ -50,9 +52,9 @@
static bool g_bootcharting_finished;
static long long get_uptime_jiffies() {
- std::string uptime;
- if (!android::base::ReadFileToString("/proc/uptime", &uptime)) return 0;
- return 100LL * strtod(uptime.c_str(), NULL);
+ constexpr int64_t kNanosecondsPerJiffy = 10000000;
+ boot_clock::time_point uptime = boot_clock::now();
+ return uptime.time_since_epoch().count() / kNanosecondsPerJiffy;
}
static std::unique_ptr<FILE, decltype(&fclose)> fopen_unique(const char* filename,
diff --git a/init/builtins.cpp b/init/builtins.cpp
index 8bd92cc..17d34e1 100644
--- a/init/builtins.cpp
+++ b/init/builtins.cpp
@@ -240,6 +240,29 @@
return Success();
}
+static Result<Success> do_interface_restart(const BuiltinArguments& args) {
+ Service* svc = ServiceList::GetInstance().FindInterface(args[1]);
+ if (!svc) return Error() << "interface " << args[1] << " not found";
+ svc->Restart();
+ return Success();
+}
+
+static Result<Success> do_interface_start(const BuiltinArguments& args) {
+ Service* svc = ServiceList::GetInstance().FindInterface(args[1]);
+ if (!svc) return Error() << "interface " << args[1] << " not found";
+ if (auto result = svc->Start(); !result) {
+ return Error() << "Could not start interface: " << result.error();
+ }
+ return Success();
+}
+
+static Result<Success> do_interface_stop(const BuiltinArguments& args) {
+ Service* svc = ServiceList::GetInstance().FindInterface(args[1]);
+ if (!svc) return Error() << "interface " << args[1] << " not found";
+ svc->Stop();
+ return Success();
+}
+
// mkdir <path> [mode] [owner] [group]
static Result<Success> do_mkdir(const BuiltinArguments& args) {
mode_t mode = 0755;
@@ -1050,6 +1073,9 @@
{"init_user0", {0, 0, {false, do_init_user0}}},
{"insmod", {1, kMax, {true, do_insmod}}},
{"installkey", {1, 1, {false, do_installkey}}},
+ {"interface_restart", {1, 1, {false, do_interface_restart}}},
+ {"interface_start", {1, 1, {false, do_interface_start}}},
+ {"interface_stop", {1, 1, {false, do_interface_stop}}},
{"load_persist_props", {0, 0, {false, do_load_persist_props}}},
{"load_system_props", {0, 0, {false, do_load_system_props}}},
{"loglevel", {1, 1, {false, do_loglevel}}},
diff --git a/init/host_init_stubs.h b/init/host_init_stubs.h
index ad48602..bb241af 100644
--- a/init/host_init_stubs.h
+++ b/init/host_init_stubs.h
@@ -35,11 +35,6 @@
std::string GetProperty(const std::string& key, const std::string& default_value);
bool GetBoolProperty(const std::string& key, bool default_value);
-template <typename T>
-T GetIntProperty(const std::string&, T default_value, T = std::numeric_limits<T>::min(),
- T = std::numeric_limits<T>::max()) {
- return default_value;
-}
} // namespace base
} // namespace android
diff --git a/init/init.cpp b/init/init.cpp
index 4fe115e..645184b 100644
--- a/init/init.cpp
+++ b/init/init.cpp
@@ -31,6 +31,10 @@
#include <sys/types.h>
#include <unistd.h>
+#include <map>
+#include <memory>
+#include <optional>
+
#include <android-base/chrono_utils.h>
#include <android-base/file.h>
#include <android-base/logging.h>
@@ -43,9 +47,6 @@
#include <private/android_filesystem_config.h>
#include <selinux/android.h>
-#include <memory>
-#include <optional>
-
#include "action_parser.h"
#include "import_parser.h"
#include "init_first_stage.h"
@@ -79,7 +80,7 @@
std::string default_console = "/dev/console";
static int epoll_fd = -1;
-static int sigterm_signal_fd = -1;
+static int signal_fd = -1;
static std::unique_ptr<Timer> waiting_for_prop(nullptr);
static std::string wait_prop_name;
@@ -130,12 +131,31 @@
}
}
-void register_epoll_handler(int fd, void (*fn)()) {
+static std::map<int, std::function<void()>> epoll_handlers;
+
+void register_epoll_handler(int fd, std::function<void()> handler) {
+ auto[it, inserted] = epoll_handlers.emplace(fd, std::move(handler));
+ if (!inserted) {
+ LOG(ERROR) << "Cannot specify two epoll handlers for a given FD";
+ return;
+ }
epoll_event ev;
ev.events = EPOLLIN;
- ev.data.ptr = reinterpret_cast<void*>(fn);
+ // std::map's iterators do not get invalidated until erased, so we use the pointer to the
+ // std::function in the map directly for epoll_ctl.
+ ev.data.ptr = reinterpret_cast<void*>(&it->second);
if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, fd, &ev) == -1) {
- PLOG(ERROR) << "epoll_ctl failed";
+ PLOG(ERROR) << "epoll_ctl failed to add fd";
+ epoll_handlers.erase(fd);
+ }
+}
+
+void unregister_epoll_handler(int fd) {
+ if (epoll_ctl(epoll_fd, EPOLL_CTL_DEL, fd, nullptr) == -1) {
+ PLOG(ERROR) << "epoll_ctl failed to remove fd";
+ }
+ if (epoll_handlers.erase(fd) != 1) {
+ LOG(ERROR) << "Attempting to remove epoll handler for FD without an existing handler";
}
}
@@ -238,6 +258,10 @@
static const std::map<std::string, ControlMessageFunction>& get_control_message_map() {
// clang-format off
static const std::map<std::string, ControlMessageFunction> control_message_functions = {
+ {"sigstop_on", {ControlTarget::SERVICE,
+ [](auto* service) { service->set_sigstop(true); return Success(); }}},
+ {"sigstop_off", {ControlTarget::SERVICE,
+ [](auto* service) { service->set_sigstop(false); return Success(); }}},
{"start", {ControlTarget::SERVICE, DoControlStart}},
{"stop", {ControlTarget::SERVICE, DoControlStop}},
{"restart", {ControlTarget::SERVICE, DoControlRestart}},
@@ -273,40 +297,29 @@
const ControlMessageFunction& function = it->second;
- if (function.target == ControlTarget::SERVICE) {
- Service* svc = ServiceList::GetInstance().FindService(name);
- if (svc == nullptr) {
- LOG(ERROR) << "No such service '" << name << "' for ctl." << msg;
- return;
- }
- if (auto result = function.action(svc); !result) {
- LOG(ERROR) << "Could not ctl." << msg << " for service " << name << ": "
- << result.error();
- }
+ Service* svc = nullptr;
+ switch (function.target) {
+ case ControlTarget::SERVICE:
+ svc = ServiceList::GetInstance().FindService(name);
+ break;
+ case ControlTarget::INTERFACE:
+ svc = ServiceList::GetInstance().FindInterface(name);
+ break;
+ default:
+ LOG(ERROR) << "Invalid function target from static map key '" << msg << "': "
+ << static_cast<std::underlying_type<ControlTarget>::type>(function.target);
+ return;
+ }
+
+ if (svc == nullptr) {
+ LOG(ERROR) << "Could not find '" << name << "' for ctl." << msg;
return;
}
- if (function.target == ControlTarget::INTERFACE) {
- for (const auto& svc : ServiceList::GetInstance()) {
- if (svc->interfaces().count(name) == 0) {
- continue;
- }
-
- if (auto result = function.action(svc.get()); !result) {
- LOG(ERROR) << "Could not handle ctl." << msg << " for service " << svc->name()
- << " with interface " << name << ": " << result.error();
- }
-
- return;
- }
-
- LOG(ERROR) << "Could not find service hosting interface " << name;
- return;
+ if (auto result = function.action(svc); !result) {
+ LOG(ERROR) << "Could not ctl." << msg << " for '" << name << "': " << result.error();
}
-
- LOG(ERROR) << "Invalid function target from static map key '" << msg
- << "': " << static_cast<std::underlying_type<ControlTarget>::type>(function.target);
}
static Result<Success> wait_for_coldboot_done_action(const BuiltinArguments& args) {
@@ -330,8 +343,8 @@
return Success();
}
-static Result<Success> keychord_init_action(const BuiltinArguments& args) {
- keychord_init();
+static Result<Success> KeychordInitAction(const BuiltinArguments& args) {
+ KeychordInit();
return Success();
}
@@ -492,14 +505,7 @@
sigaction(SIGTRAP, &action, nullptr);
}
-static void HandleSigtermSignal() {
- signalfd_siginfo siginfo;
- ssize_t bytes_read = TEMP_FAILURE_RETRY(read(sigterm_signal_fd, &siginfo, sizeof(siginfo)));
- if (bytes_read != sizeof(siginfo)) {
- PLOG(ERROR) << "Failed to read siginfo from sigterm_signal_fd";
- return;
- }
-
+static void HandleSigtermSignal(const signalfd_siginfo& siginfo) {
if (siginfo.ssi_pid != 0) {
// Drop any userspace SIGTERM requests.
LOG(DEBUG) << "Ignoring SIGTERM from pid " << siginfo.ssi_pid;
@@ -509,37 +515,73 @@
HandlePowerctlMessage("shutdown,container");
}
-static void UnblockSigterm() {
- sigset_t mask;
- sigemptyset(&mask);
- sigaddset(&mask, SIGTERM);
+static void HandleSignalFd() {
+ signalfd_siginfo siginfo;
+ ssize_t bytes_read = TEMP_FAILURE_RETRY(read(signal_fd, &siginfo, sizeof(siginfo)));
+ if (bytes_read != sizeof(siginfo)) {
+ PLOG(ERROR) << "Failed to read siginfo from signal_fd";
+ return;
+ }
- if (sigprocmask(SIG_UNBLOCK, &mask, nullptr) == -1) {
- PLOG(FATAL) << "failed to unblock SIGTERM for PID " << getpid();
+ switch (siginfo.ssi_signo) {
+ case SIGCHLD:
+ ReapAnyOutstandingChildren();
+ break;
+ case SIGTERM:
+ HandleSigtermSignal(siginfo);
+ break;
+ default:
+ PLOG(ERROR) << "signal_fd: received unexpected signal " << siginfo.ssi_signo;
+ break;
}
}
-static void InstallSigtermHandler() {
+static void UnblockSignals() {
+ const struct sigaction act { .sa_handler = SIG_DFL };
+ sigaction(SIGCHLD, &act, nullptr);
+
sigset_t mask;
sigemptyset(&mask);
+ sigaddset(&mask, SIGCHLD);
sigaddset(&mask, SIGTERM);
- if (sigprocmask(SIG_BLOCK, &mask, nullptr) == -1) {
- PLOG(FATAL) << "failed to block SIGTERM";
+ if (sigprocmask(SIG_UNBLOCK, &mask, nullptr) == -1) {
+ PLOG(FATAL) << "failed to unblock signals for PID " << getpid();
+ }
+}
+
+static void InstallSignalFdHandler() {
+ // Applying SA_NOCLDSTOP to a defaulted SIGCHLD handler prevents the signalfd from receiving
+ // SIGCHLD when a child process stops or continues (b/77867680#comment9).
+ const struct sigaction act { .sa_handler = SIG_DFL, .sa_flags = SA_NOCLDSTOP };
+ sigaction(SIGCHLD, &act, nullptr);
+
+ sigset_t mask;
+ sigemptyset(&mask);
+ sigaddset(&mask, SIGCHLD);
+
+ if (!IsRebootCapable()) {
+ // If init does not have the CAP_SYS_BOOT capability, it is running in a container.
+ // In that case, receiving SIGTERM will cause the system to shut down.
+ sigaddset(&mask, SIGTERM);
}
- // Register a handler to unblock SIGTERM in the child processes.
- const int result = pthread_atfork(nullptr, nullptr, &UnblockSigterm);
+ if (sigprocmask(SIG_BLOCK, &mask, nullptr) == -1) {
+ PLOG(FATAL) << "failed to block signals";
+ }
+
+ // Register a handler to unblock signals in the child processes.
+ const int result = pthread_atfork(nullptr, nullptr, &UnblockSignals);
if (result != 0) {
LOG(FATAL) << "Failed to register a fork handler: " << strerror(result);
}
- sigterm_signal_fd = signalfd(-1, &mask, SFD_CLOEXEC);
- if (sigterm_signal_fd == -1) {
- PLOG(FATAL) << "failed to create signalfd for SIGTERM";
+ signal_fd = signalfd(-1, &mask, SFD_CLOEXEC);
+ if (signal_fd == -1) {
+ PLOG(FATAL) << "failed to create signalfd";
}
- register_epoll_handler(sigterm_signal_fd, HandleSigtermSignal);
+ register_epoll_handler(signal_fd, HandleSignalFd);
}
int main(int argc, char** argv) {
@@ -690,13 +732,7 @@
PLOG(FATAL) << "epoll_create1 failed";
}
- sigchld_handler_init();
-
- if (!IsRebootCapable()) {
- // If init does not have the CAP_SYS_BOOT capability, it is running in a container.
- // In that case, receiving SIGTERM will cause the system to shut down.
- InstallSigtermHandler();
- }
+ InstallSignalFdHandler();
property_load_boot_defaults();
export_oem_lock_status();
@@ -725,7 +761,7 @@
am.QueueBuiltinAction(MixHwrngIntoLinuxRngAction, "MixHwrngIntoLinuxRng");
am.QueueBuiltinAction(SetMmapRndBitsAction, "SetMmapRndBits");
am.QueueBuiltinAction(SetKptrRestrictAction, "SetKptrRestrict");
- am.QueueBuiltinAction(keychord_init_action, "keychord_init");
+ am.QueueBuiltinAction(KeychordInitAction, "KeychordInit");
am.QueueBuiltinAction(console_init_action, "console_init");
// Trigger all the boot actions to get us started.
@@ -782,7 +818,7 @@
if (nr == -1) {
PLOG(ERROR) << "epoll_wait failed";
} else if (nr == 1) {
- ((void (*)()) ev.data.ptr)();
+ std::invoke(*reinterpret_cast<std::function<void()>*>(ev.data.ptr));
}
}
diff --git a/init/init.h b/init/init.h
index d4a0e96..e7c4d8d 100644
--- a/init/init.h
+++ b/init/init.h
@@ -19,6 +19,7 @@
#include <sys/types.h>
+#include <functional>
#include <string>
#include <vector>
@@ -42,7 +43,8 @@
void property_changed(const std::string& name, const std::string& value);
-void register_epoll_handler(int fd, void (*fn)());
+void register_epoll_handler(int fd, std::function<void()> handler);
+void unregister_epoll_handler(int fd);
bool start_waiting_for_property(const char *name, const char *value);
diff --git a/init/init_first_stage.cpp b/init/init_first_stage.cpp
index 033ce41..34de640 100644
--- a/init/init_first_stage.cpp
+++ b/init/init_first_stage.cpp
@@ -33,11 +33,13 @@
#include "devices.h"
#include "fs_mgr.h"
#include "fs_mgr_avb.h"
+#include "fs_mgr_dm_linear.h"
#include "uevent.h"
#include "uevent_listener.h"
#include "util.h"
using android::base::Timer;
+using android::fs_mgr::LogicalPartitionTable;
namespace android {
namespace init {
@@ -58,18 +60,21 @@
protected:
ListenerAction HandleBlockDevice(const std::string& name, const Uevent&);
bool InitRequiredDevices();
- bool InitVerityDevice(const std::string& verity_device);
+ bool InitMappedDevice(const std::string& verity_device);
+ bool CreateLogicalPartitions();
bool MountPartitions();
+ bool GetBackingDmLinearDevices();
virtual ListenerAction UeventCallback(const Uevent& uevent);
// Pure virtual functions.
- virtual bool GetRequiredDevices() = 0;
+ virtual bool GetDmVerityDevices() = 0;
virtual bool SetUpDmVerity(fstab_rec* fstab_rec) = 0;
bool need_dm_verity_;
std::unique_ptr<fstab, decltype(&fs_mgr_free_fstab)> device_tree_fstab_;
+ std::unique_ptr<LogicalPartitionTable> dm_linear_table_;
std::vector<fstab_rec*> mount_fstab_recs_;
std::set<std::string> required_devices_partition_names_;
std::unique_ptr<DeviceHandler> device_handler_;
@@ -82,7 +87,7 @@
~FirstStageMountVBootV1() override = default;
protected:
- bool GetRequiredDevices() override;
+ bool GetDmVerityDevices() override;
bool SetUpDmVerity(fstab_rec* fstab_rec) override;
};
@@ -95,7 +100,7 @@
protected:
ListenerAction UeventCallback(const Uevent& uevent) override;
- bool GetRequiredDevices() override;
+ bool GetDmVerityDevices() override;
bool SetUpDmVerity(fstab_rec* fstab_rec) override;
bool InitAvbHandle();
@@ -114,18 +119,33 @@
return access("/sbin/recovery", F_OK) == 0;
}
+static inline bool IsDmLinearEnabled() {
+ bool enabled = false;
+ import_kernel_cmdline(
+ false, [&enabled](const std::string& key, const std::string& value, bool in_qemu) {
+ if (key == "androidboot.lrap" && value == "1") {
+ enabled = true;
+ }
+ });
+ return enabled;
+}
+
// Class Definitions
// -----------------
FirstStageMount::FirstStageMount()
: need_dm_verity_(false), device_tree_fstab_(fs_mgr_read_fstab_dt(), fs_mgr_free_fstab) {
- if (!device_tree_fstab_) {
+ if (device_tree_fstab_) {
+ // Stores device_tree_fstab_->recs[] into mount_fstab_recs_ (vector<fstab_rec*>)
+ // for easier manipulation later, e.g., range-base for loop.
+ for (int i = 0; i < device_tree_fstab_->num_entries; i++) {
+ mount_fstab_recs_.push_back(&device_tree_fstab_->recs[i]);
+ }
+ } else {
LOG(INFO) << "Failed to read fstab from device tree";
- return;
}
- // Stores device_tree_fstab_->recs[] into mount_fstab_recs_ (vector<fstab_rec*>)
- // for easier manipulation later, e.g., range-base for loop.
- for (int i = 0; i < device_tree_fstab_->num_entries; i++) {
- mount_fstab_recs_.push_back(&device_tree_fstab_->recs[i]);
+
+ if (IsDmLinearEnabled()) {
+ dm_linear_table_ = android::fs_mgr::LoadPartitionsFromDeviceTree();
}
auto boot_devices = fs_mgr_get_boot_devices();
@@ -143,18 +163,38 @@
}
bool FirstStageMount::DoFirstStageMount() {
- // Nothing to mount.
- if (mount_fstab_recs_.empty()) return true;
+ if (!dm_linear_table_ && mount_fstab_recs_.empty()) {
+ // Nothing to mount.
+ LOG(INFO) << "First stage mount skipped (missing/incompatible/empty fstab in device tree)";
+ return true;
+ }
if (!InitDevices()) return false;
+ if (!CreateLogicalPartitions()) return false;
+
if (!MountPartitions()) return false;
return true;
}
bool FirstStageMount::InitDevices() {
- return GetRequiredDevices() && InitRequiredDevices();
+ return GetBackingDmLinearDevices() && GetDmVerityDevices() && InitRequiredDevices();
+}
+
+bool FirstStageMount::GetBackingDmLinearDevices() {
+ // Add any additional devices required for dm-linear mappings.
+ if (!dm_linear_table_) {
+ return true;
+ }
+
+ for (const auto& partition : dm_linear_table_->partitions) {
+ for (const auto& extent : partition.extents) {
+ const std::string& partition_name = android::base::Basename(extent.block_device());
+ required_devices_partition_names_.emplace(partition_name);
+ }
+ }
+ return true;
}
// Creates devices with uevent->partition_name matching one in the member variable
@@ -165,7 +205,7 @@
return true;
}
- if (need_dm_verity_) {
+ if (dm_linear_table_ || need_dm_verity_) {
const std::string dm_path = "/devices/virtual/misc/device-mapper";
bool found = false;
auto dm_callback = [this, &dm_path, &found](const Uevent& uevent) {
@@ -212,6 +252,13 @@
return true;
}
+bool FirstStageMount::CreateLogicalPartitions() {
+ if (!dm_linear_table_) {
+ return true;
+ }
+ return android::fs_mgr::CreateLogicalPartitions(*dm_linear_table_.get());
+}
+
ListenerAction FirstStageMount::HandleBlockDevice(const std::string& name, const Uevent& uevent) {
// Matches partition name to create device nodes.
// Both required_devices_partition_names_ and uevent->partition_name have A/B
@@ -249,14 +296,14 @@
}
// Creates "/dev/block/dm-XX" for dm-verity by running coldboot on /sys/block/dm-XX.
-bool FirstStageMount::InitVerityDevice(const std::string& verity_device) {
- const std::string device_name(basename(verity_device.c_str()));
+bool FirstStageMount::InitMappedDevice(const std::string& dm_device) {
+ const std::string device_name(basename(dm_device.c_str()));
const std::string syspath = "/sys/block/" + device_name;
bool found = false;
- auto verity_callback = [&device_name, &verity_device, this, &found](const Uevent& uevent) {
+ auto verity_callback = [&device_name, &dm_device, this, &found](const Uevent& uevent) {
if (uevent.device_name == device_name) {
- LOG(VERBOSE) << "Creating dm-verity device : " << verity_device;
+ LOG(VERBOSE) << "Creating device-mapper device : " << dm_device;
device_handler_->HandleDeviceEvent(uevent);
found = true;
return ListenerAction::kStop;
@@ -281,6 +328,14 @@
bool FirstStageMount::MountPartitions() {
for (auto fstab_rec : mount_fstab_recs_) {
+ if (fs_mgr_is_logical(fstab_rec)) {
+ if (!fs_mgr_update_logical_partition(fstab_rec)) {
+ return false;
+ }
+ if (!InitMappedDevice(fstab_rec->blk_device)) {
+ return false;
+ }
+ }
if (!SetUpDmVerity(fstab_rec)) {
PLOG(ERROR) << "Failed to setup verity for '" << fstab_rec->mount_point << "'";
return false;
@@ -293,7 +348,7 @@
return true;
}
-bool FirstStageMountVBootV1::GetRequiredDevices() {
+bool FirstStageMountVBootV1::GetDmVerityDevices() {
std::string verity_loc_device;
need_dm_verity_ = false;
@@ -346,7 +401,7 @@
// The exact block device name (fstab_rec->blk_device) is changed to
// "/dev/block/dm-XX". Needs to create it because ueventd isn't started in init
// first stage.
- return InitVerityDevice(fstab_rec->blk_device);
+ return InitMappedDevice(fstab_rec->blk_device);
default:
return false;
}
@@ -373,7 +428,7 @@
}
}
-bool FirstStageMountVBootV2::GetRequiredDevices() {
+bool FirstStageMountVBootV2::GetDmVerityDevices() {
need_dm_verity_ = false;
// fstab_rec->blk_device has A/B suffix.
@@ -445,7 +500,7 @@
// The exact block device name (fstab_rec->blk_device) is changed to
// "/dev/block/dm-XX". Needs to create it because ueventd isn't started in init
// first stage.
- return InitVerityDevice(fstab_rec->blk_device);
+ return InitMappedDevice(fstab_rec->blk_device);
default:
return false;
}
@@ -483,12 +538,6 @@
return true;
}
- // Firstly checks if device tree fstab entries are compatible.
- if (!is_android_dt_value_expected("fstab/compatible", "android,fstab")) {
- LOG(INFO) << "First stage mount skipped (missing/incompatible fstab in device tree)";
- return true;
- }
-
std::unique_ptr<FirstStageMount> handle = FirstStageMount::Create();
if (!handle) {
LOG(ERROR) << "Failed to create FirstStageMount";
diff --git a/init/keychords.cpp b/init/keychords.cpp
index e686ce1..293736d 100644
--- a/init/keychords.cpp
+++ b/init/keychords.cpp
@@ -16,13 +16,22 @@
#include "keychords.h"
+#include <dirent.h>
#include <fcntl.h>
-#include <stdlib.h>
-#include <sys/stat.h>
+#include <linux/input.h>
+#include <sys/cdefs.h>
+#include <sys/inotify.h>
+#include <sys/ioctl.h>
#include <sys/types.h>
-#include <linux/keychord.h>
#include <unistd.h>
+#include <algorithm>
+#include <functional>
+#include <map>
+#include <memory>
+#include <string>
+#include <vector>
+
#include <android-base/logging.h>
#include <android-base/properties.h>
@@ -31,51 +40,89 @@
namespace android {
namespace init {
-static struct input_keychord *keychords = 0;
-static int keychords_count = 0;
-static int keychords_length = 0;
-static int keychord_fd = -1;
+namespace {
-void add_service_keycodes(Service* svc)
-{
- struct input_keychord *keychord;
- size_t i, size;
+int keychords_count;
- if (!svc->keycodes().empty()) {
- /* add a new keychord to the list */
- size = sizeof(*keychord) + svc->keycodes().size() * sizeof(keychord->keycodes[0]);
- keychords = (input_keychord*) realloc(keychords, keychords_length + size);
- if (!keychords) {
- PLOG(ERROR) << "could not allocate keychords";
- keychords_length = 0;
- keychords_count = 0;
- return;
+struct KeychordEntry {
+ const std::vector<int> keycodes;
+ bool notified;
+ int id;
+
+ KeychordEntry(const std::vector<int>& keycodes, int id)
+ : keycodes(keycodes), notified(false), id(id) {}
+};
+
+std::vector<KeychordEntry> keychord_entries;
+
+// Bit management
+class KeychordMask {
+ private:
+ typedef unsigned int mask_t;
+ std::vector<mask_t> bits;
+ static constexpr size_t bits_per_byte = 8;
+
+ public:
+ explicit KeychordMask(size_t bit = 0) : bits((bit + sizeof(mask_t) - 1) / sizeof(mask_t), 0) {}
+
+ void SetBit(size_t bit, bool value = true) {
+ auto idx = bit / (bits_per_byte * sizeof(mask_t));
+ if (idx >= bits.size()) return;
+ if (value) {
+ bits[idx] |= mask_t(1) << (bit % (bits_per_byte * sizeof(mask_t)));
+ } else {
+ bits[idx] &= ~(mask_t(1) << (bit % (bits_per_byte * sizeof(mask_t))));
}
-
- keychord = (struct input_keychord *)((char *)keychords + keychords_length);
- keychord->version = KEYCHORD_VERSION;
- keychord->id = keychords_count + 1;
- keychord->count = svc->keycodes().size();
- svc->set_keychord_id(keychord->id);
-
- for (i = 0; i < svc->keycodes().size(); i++) {
- keychord->keycodes[i] = svc->keycodes()[i];
- }
- keychords_count++;
- keychords_length += size;
- }
-}
-
-static void handle_keychord() {
- int ret;
- __u16 id;
-
- ret = read(keychord_fd, &id, sizeof(id));
- if (ret != sizeof(id)) {
- PLOG(ERROR) << "could not read keychord id";
- return;
}
+ bool GetBit(size_t bit) const {
+ auto idx = bit / (bits_per_byte * sizeof(mask_t));
+ return bits[idx] & (mask_t(1) << (bit % (bits_per_byte * sizeof(mask_t))));
+ }
+
+ size_t bytesize() const { return bits.size() * sizeof(mask_t); }
+ void* data() { return bits.data(); }
+ size_t size() const { return bits.size() * sizeof(mask_t) * bits_per_byte; }
+ void resize(size_t bit) {
+ auto idx = bit / (bits_per_byte * sizeof(mask_t));
+ if (idx >= bits.size()) {
+ bits.resize(idx + 1, 0);
+ }
+ }
+
+ operator bool() const {
+ for (size_t i = 0; i < bits.size(); ++i) {
+ if (bits[i]) return true;
+ }
+ return false;
+ }
+
+ KeychordMask operator&(const KeychordMask& rval) const {
+ auto len = std::min(bits.size(), rval.bits.size());
+ KeychordMask ret;
+ ret.bits.resize(len);
+ for (size_t i = 0; i < len; ++i) {
+ ret.bits[i] = bits[i] & rval.bits[i];
+ }
+ return ret;
+ }
+
+ void operator|=(const KeychordMask& rval) {
+ size_t len = rval.bits.size();
+ bits.resize(len);
+ for (size_t i = 0; i < len; ++i) {
+ bits[i] |= rval.bits[i];
+ }
+ }
+};
+
+KeychordMask keychord_current;
+
+constexpr char kDevicePath[] = "/dev/input";
+
+std::map<std::string, int> keychord_registration;
+
+void HandleKeychord(int id) {
// Only handle keychords if adb is enabled.
std::string adb_enabled = android::base::GetProperty("init.svc.adbd", "");
if (adb_enabled == "running") {
@@ -94,32 +141,179 @@
}
}
-void keychord_init() {
+void KeychordLambdaCheck() {
+ for (auto& e : keychord_entries) {
+ bool found = true;
+ for (auto& code : e.keycodes) {
+ if (!keychord_current.GetBit(code)) {
+ e.notified = false;
+ found = false;
+ break;
+ }
+ }
+ if (!found) continue;
+ if (e.notified) continue;
+ e.notified = true;
+ HandleKeychord(e.id);
+ }
+}
+
+void KeychordLambdaHandler(int fd) {
+ input_event event;
+ auto res = TEMP_FAILURE_RETRY(::read(fd, &event, sizeof(event)));
+ if ((res != sizeof(event)) || (event.type != EV_KEY)) return;
+ keychord_current.SetBit(event.code, event.value);
+ KeychordLambdaCheck();
+}
+
+bool KeychordGeteventEnable(int fd) {
+ static bool EviocsmaskSupported = true;
+
+ // Make sure it is an event channel, should pass this ioctl call
+ int version;
+ if (::ioctl(fd, EVIOCGVERSION, &version)) return false;
+
+ if (EviocsmaskSupported) {
+ KeychordMask mask(EV_KEY);
+ mask.SetBit(EV_KEY);
+ input_mask msg = {};
+ msg.type = EV_SYN;
+ msg.codes_size = mask.bytesize();
+ msg.codes_ptr = reinterpret_cast<uintptr_t>(mask.data());
+ if (::ioctl(fd, EVIOCSMASK, &msg) == -1) {
+ PLOG(WARNING) << "EVIOCSMASK not supported";
+ EviocsmaskSupported = false;
+ }
+ }
+
+ KeychordMask mask;
+ for (auto& e : keychord_entries) {
+ for (auto& code : e.keycodes) {
+ mask.resize(code);
+ mask.SetBit(code);
+ }
+ }
+
+ keychord_current.resize(mask.size());
+ KeychordMask available(mask.size());
+ auto res = ::ioctl(fd, EVIOCGBIT(EV_KEY, available.bytesize()), available.data());
+ if (res == -1) return false;
+ if (!(available & mask)) return false;
+
+ if (EviocsmaskSupported) {
+ input_mask msg = {};
+ msg.type = EV_KEY;
+ msg.codes_size = mask.bytesize();
+ msg.codes_ptr = reinterpret_cast<uintptr_t>(mask.data());
+ ::ioctl(fd, EVIOCSMASK, &msg);
+ }
+
+ KeychordMask set(mask.size());
+ res = ::ioctl(fd, EVIOCGKEY(res), set.data());
+ if (res > 0) {
+ keychord_current |= mask & available & set;
+ KeychordLambdaCheck();
+ }
+ register_epoll_handler(fd, [fd]() { KeychordLambdaHandler(fd); });
+ return true;
+}
+
+void GeteventOpenDevice(const std::string& device) {
+ if (keychord_registration.count(device)) return;
+ auto fd = TEMP_FAILURE_RETRY(::open(device.c_str(), O_RDWR | O_CLOEXEC));
+ if (fd == -1) {
+ PLOG(ERROR) << "Can not open " << device;
+ return;
+ }
+ if (!KeychordGeteventEnable(fd)) {
+ ::close(fd);
+ } else {
+ keychord_registration.emplace(device, fd);
+ }
+}
+
+void GeteventCloseDevice(const std::string& device) {
+ auto it = keychord_registration.find(device);
+ if (it == keychord_registration.end()) return;
+ auto fd = (*it).second;
+ unregister_epoll_handler(fd);
+ keychord_registration.erase(it);
+ ::close(fd);
+}
+
+int inotify_fd = -1;
+
+void InotifyHandler() {
+ unsigned char buf[512];
+
+ auto res = TEMP_FAILURE_RETRY(::read(inotify_fd, buf, sizeof(buf)));
+ if (res < 0) {
+ PLOG(WARNING) << "could not get event";
+ return;
+ }
+
+ auto event_buf = buf;
+ while (static_cast<size_t>(res) >= sizeof(inotify_event)) {
+ auto event = reinterpret_cast<inotify_event*>(event_buf);
+ auto event_size = sizeof(inotify_event) + event->len;
+ if (static_cast<size_t>(res) < event_size) break;
+ if (event->len) {
+ std::string devname(kDevicePath);
+ devname += '/';
+ devname += event->name;
+ if (event->mask & IN_CREATE) {
+ GeteventOpenDevice(devname);
+ } else {
+ GeteventCloseDevice(devname);
+ }
+ }
+ res -= event_size;
+ event_buf += event_size;
+ }
+}
+
+void GeteventOpenDevice() {
+ inotify_fd = ::inotify_init1(IN_NONBLOCK | IN_CLOEXEC);
+ if (inotify_fd < 0) {
+ PLOG(WARNING) << "Could not instantiate inotify for " << kDevicePath;
+ } else if (::inotify_add_watch(inotify_fd, kDevicePath, IN_DELETE | IN_CREATE | IN_ONLYDIR) < 0) {
+ PLOG(WARNING) << "Could not add watch for " << kDevicePath;
+ ::close(inotify_fd);
+ inotify_fd = -1;
+ }
+
+ std::unique_ptr<DIR, decltype(&closedir)> device(opendir(kDevicePath), closedir);
+ if (device) {
+ dirent* entry;
+ while ((entry = readdir(device.get()))) {
+ if (entry->d_name[0] == '.') continue;
+ std::string devname(kDevicePath);
+ devname += '/';
+ devname += entry->d_name;
+ GeteventOpenDevice(devname);
+ }
+ }
+
+ if (inotify_fd >= 0) register_epoll_handler(inotify_fd, InotifyHandler);
+}
+
+void AddServiceKeycodes(Service* svc) {
+ if (svc->keycodes().empty()) return;
+ for (auto& code : svc->keycodes()) {
+ if ((code < 0) || (code >= KEY_MAX)) return;
+ }
+ ++keychords_count;
+ keychord_entries.emplace_back(KeychordEntry(svc->keycodes(), keychords_count));
+ svc->set_keychord_id(keychords_count);
+}
+
+} // namespace
+
+void KeychordInit() {
for (const auto& service : ServiceList::GetInstance()) {
- add_service_keycodes(service.get());
+ AddServiceKeycodes(service.get());
}
-
- // Nothing to do if no services require keychords.
- if (!keychords) {
- return;
- }
-
- keychord_fd = TEMP_FAILURE_RETRY(open("/dev/keychord", O_RDWR | O_CLOEXEC));
- if (keychord_fd == -1) {
- PLOG(ERROR) << "could not open /dev/keychord";
- return;
- }
-
- int ret = write(keychord_fd, keychords, keychords_length);
- if (ret != keychords_length) {
- PLOG(ERROR) << "could not configure /dev/keychord " << ret;
- close(keychord_fd);
- }
-
- free(keychords);
- keychords = nullptr;
-
- register_epoll_handler(keychord_fd, handle_keychord);
+ if (keychords_count) GeteventOpenDevice();
}
} // namespace init
diff --git a/init/keychords.h b/init/keychords.h
index 1c34098..689a3b5 100644
--- a/init/keychords.h
+++ b/init/keychords.h
@@ -22,8 +22,7 @@
namespace android {
namespace init {
-void add_service_keycodes(Service* svc);
-void keychord_init();
+void KeychordInit();
} // namespace init
} // namespace android
diff --git a/init/property_service.cpp b/init/property_service.cpp
index c3100a5..47e45ef 100644
--- a/init/property_service.cpp
+++ b/init/property_service.cpp
@@ -65,7 +65,6 @@
using namespace std::literals;
-using android::base::GetIntProperty;
using android::base::ReadFileToString;
using android::base::Split;
using android::base::StartsWith;
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 09d8dae..0e08d9b 100644
--- a/init/service.cpp
+++ b/init/service.cpp
@@ -34,6 +34,7 @@
#include <android-base/parseint.h>
#include <android-base/stringprintf.h>
#include <android-base/strings.h>
+#include <android-base/unique_fd.h>
#include <hidl-util/FQName.h>
#include <processgroup/processgroup.h>
#include <selinux/selinux.h>
@@ -59,13 +60,13 @@
using android::base::ParseInt;
using android::base::StartsWith;
using android::base::StringPrintf;
+using android::base::unique_fd;
using android::base::WriteStringToFile;
namespace android {
namespace init {
-static Result<std::string> ComputeContextFromExecutable(std::string& service_name,
- const std::string& service_path) {
+static Result<std::string> ComputeContextFromExecutable(const std::string& service_path) {
std::string computed_context;
char* raw_con = nullptr;
@@ -101,36 +102,49 @@
return computed_context;
}
-static void SetUpPidNamespace(const std::string& service_name) {
+Result<Success> Service::SetUpMountNamespace() const {
constexpr unsigned int kSafeFlags = MS_NODEV | MS_NOEXEC | MS_NOSUID;
- // It's OK to LOG(FATAL) in this function since it's running in the first
- // child process.
-
// Recursively remount / as slave like zygote does so unmounting and mounting /proc
// doesn't interfere with the parent namespace's /proc mount. This will also
// prevent any other mounts/unmounts initiated by the service from interfering
// with the parent namespace but will still allow mount events from the parent
// namespace to propagate to the child.
if (mount("rootfs", "/", nullptr, (MS_SLAVE | MS_REC), nullptr) == -1) {
- PLOG(FATAL) << "couldn't remount(/) recursively as slave for " << service_name;
- }
- // umount() then mount() /proc.
- // Note that it is not sufficient to mount with MS_REMOUNT.
- if (umount("/proc") == -1) {
- PLOG(FATAL) << "couldn't umount(/proc) for " << service_name;
- }
- if (mount("", "/proc", "proc", kSafeFlags, "") == -1) {
- PLOG(FATAL) << "couldn't mount(/proc) for " << service_name;
+ return ErrnoError() << "Could not remount(/) recursively as slave";
}
- if (prctl(PR_SET_NAME, service_name.c_str()) == -1) {
- PLOG(FATAL) << "couldn't set name for " << service_name;
+ // umount() then mount() /proc and/or /sys
+ // Note that it is not sufficient to mount with MS_REMOUNT.
+ if (namespace_flags_ & CLONE_NEWPID) {
+ if (umount("/proc") == -1) {
+ return ErrnoError() << "Could not umount(/proc)";
+ }
+ if (mount("", "/proc", "proc", kSafeFlags, "") == -1) {
+ return ErrnoError() << "Could not mount(/proc)";
+ }
+ }
+ bool remount_sys = std::any_of(namespaces_to_enter_.begin(), namespaces_to_enter_.end(),
+ [](const auto& entry) { return entry.first == CLONE_NEWNET; });
+ if (remount_sys) {
+ if (umount2("/sys", MNT_DETACH) == -1) {
+ return ErrnoError() << "Could not umount(/sys)";
+ }
+ if (mount("", "/sys", "sys", kSafeFlags, "") == -1) {
+ return ErrnoError() << "Could not mount(/sys)";
+ }
+ }
+ return Success();
+}
+
+Result<Success> Service::SetUpPidNamespace() const {
+ if (prctl(PR_SET_NAME, name_.c_str()) == -1) {
+ return ErrnoError() << "Could not set name";
}
pid_t child_pid = fork();
if (child_pid == -1) {
- PLOG(FATAL) << "couldn't fork init inside the PID namespace for " << service_name;
+ return ErrnoError() << "Could not fork init inside the PID namespace";
}
if (child_pid > 0) {
@@ -153,9 +167,23 @@
}
_exit(WEXITSTATUS(init_exitstatus));
}
+ return Success();
}
-static bool ExpandArgsAndExecv(const std::vector<std::string>& args) {
+Result<Success> Service::EnterNamespaces() const {
+ for (const auto& [nstype, path] : namespaces_to_enter_) {
+ auto fd = unique_fd{open(path.c_str(), O_RDONLY | O_CLOEXEC)};
+ if (!fd) {
+ return ErrnoError() << "Could not open namespace at " << path;
+ }
+ if (setns(fd, nstype) == -1) {
+ return ErrnoError() << "Could not setns() namespace at " << path;
+ }
+ }
+ return Success();
+}
+
+static bool ExpandArgsAndExecv(const std::vector<std::string>& args, bool sigstop) {
std::vector<std::string> expanded_args;
std::vector<char*> c_strings;
@@ -169,6 +197,10 @@
}
c_strings.push_back(nullptr);
+ if (sigstop) {
+ kill(getpid(), SIGSTOP);
+ }
+
return execv(c_strings[0], c_strings.data()) == 0;
}
@@ -418,6 +450,20 @@
return Success();
}
+Result<Success> Service::ParseEnterNamespace(const std::vector<std::string>& args) {
+ if (args[1] != "net") {
+ return Error() << "Init only supports entering network namespaces";
+ }
+ if (!namespaces_to_enter_.empty()) {
+ return Error() << "Only one network namespace may be entered";
+ }
+ // Network namespaces require that /sys is remounted, otherwise the old adapters will still be
+ // present. Therefore, they also require mount namespaces.
+ namespace_flags_ |= CLONE_NEWNS;
+ namespaces_to_enter_.emplace_back(CLONE_NEWNET, args[2]);
+ return Success();
+}
+
Result<Success> Service::ParseGroup(const std::vector<std::string>& args) {
auto gid = DecodeUid(args[1]);
if (!gid) {
@@ -450,8 +496,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 << "'";
}
@@ -582,6 +628,11 @@
return Success();
}
+Result<Success> Service::ParseSigstop(const std::vector<std::string>& args) {
+ sigstop_ = true;
+ return Success();
+}
+
Result<Success> Service::ParseSetenv(const std::vector<std::string>& args) {
environment_vars_.emplace_back(args[1], args[2]);
return Success();
@@ -682,29 +733,32 @@
{"console", {0, 1, &Service::ParseConsole}},
{"critical", {0, 0, &Service::ParseCritical}},
{"disabled", {0, 0, &Service::ParseDisabled}},
+ {"enter_namespace",
+ {2, 2, &Service::ParseEnterNamespace}},
+ {"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}},
+ {"sigstop", {0, 0, &Service::ParseSigstop}},
{"socket", {3, 6, &Service::ParseSocket}},
- {"file", {2, 2, &Service::ParseFile}},
{"user", {1, 1, &Service::ParseUser}},
{"writepid", {1, kMax, &Service::ParseWritepid}},
};
@@ -783,7 +837,7 @@
if (!seclabel_.empty()) {
scon = seclabel_;
} else {
- auto result = ComputeContextFromExecutable(name_, args_[0]);
+ auto result = ComputeContextFromExecutable(args_[0]);
if (!result) {
return result.error();
}
@@ -802,10 +856,24 @@
if (pid == 0) {
umask(077);
+ if (auto result = EnterNamespaces(); !result) {
+ LOG(FATAL) << "Service '" << name_ << "' could not enter namespaces: " << result.error();
+ }
+
+ if (namespace_flags_ & CLONE_NEWNS) {
+ if (auto result = SetUpMountNamespace(); !result) {
+ LOG(FATAL) << "Service '" << name_
+ << "' could not set up mount namespace: " << result.error();
+ }
+ }
+
if (namespace_flags_ & CLONE_NEWPID) {
// This will fork again to run an init process inside the PID
// namespace.
- SetUpPidNamespace(name_);
+ if (auto result = SetUpPidNamespace(); !result) {
+ LOG(FATAL) << "Service '" << name_
+ << "' could not set up PID namespace: " << result.error();
+ }
}
for (const auto& [key, value] : environment_vars_) {
@@ -862,7 +930,7 @@
// priority. Aborts on failure.
SetProcessAttributes();
- if (!ExpandArgsAndExecv(args_)) {
+ if (!ExpandArgsAndExecv(args_, sigstop_)) {
PLOG(ERROR) << "cannot execve('" << args_[0] << "')";
}
diff --git a/init/service.h b/init/service.h
index bcf1943..cbfd52f 100644
--- a/init/service.h
+++ b/init/service.h
@@ -118,12 +118,16 @@
bool is_override() const { return override_; }
bool process_cgroup_empty() const { return process_cgroup_empty_; }
unsigned long start_order() const { return start_order_; }
+ void set_sigstop(bool value) { sigstop_ = value; }
const std::vector<std::string>& args() const { return args_; }
private:
using OptionParser = Result<Success> (Service::*)(const std::vector<std::string>& args);
class OptionParserMap;
+ Result<Success> SetUpMountNamespace() const;
+ Result<Success> SetUpPidNamespace() const;
+ Result<Success> EnterNamespaces() const;
void NotifyStateChange(const std::string& new_state) const;
void StopOrReset(int how);
void ZapStdio() const;
@@ -136,6 +140,7 @@
Result<Success> ParseConsole(const std::vector<std::string>& args);
Result<Success> ParseCritical(const std::vector<std::string>& args);
Result<Success> ParseDisabled(const std::vector<std::string>& args);
+ Result<Success> ParseEnterNamespace(const std::vector<std::string>& args);
Result<Success> ParseGroup(const std::vector<std::string>& args);
Result<Success> ParsePriority(const std::vector<std::string>& args);
Result<Success> ParseInterface(const std::vector<std::string>& args);
@@ -153,6 +158,7 @@
Result<Success> ParseSeclabel(const std::vector<std::string>& args);
Result<Success> ParseSetenv(const std::vector<std::string>& args);
Result<Success> ParseShutdown(const std::vector<std::string>& args);
+ Result<Success> ParseSigstop(const std::vector<std::string>& args);
Result<Success> ParseSocket(const std::vector<std::string>& args);
Result<Success> ParseFile(const std::vector<std::string>& args);
Result<Success> ParseUser(const std::vector<std::string>& args);
@@ -179,6 +185,8 @@
std::vector<gid_t> supp_gids_;
CapSet capabilities_;
unsigned namespace_flags_;
+ // Pair of namespace type, path to namespace.
+ std::vector<std::pair<int, std::string>> namespaces_to_enter_;
std::string seclabel_;
@@ -213,6 +221,8 @@
std::vector<std::pair<int, rlimit>> rlimits_;
+ bool sigstop_ = false;
+
std::vector<std::string> args_;
std::vector<std::function<void(const siginfo_t& siginfo)>> reap_callbacks_;
@@ -240,6 +250,16 @@
return nullptr;
}
+ Service* FindInterface(const std::string& interface_name) {
+ for (const auto& svc : services_) {
+ if (svc->interfaces().count(interface_name) > 0) {
+ return svc.get();
+ }
+ }
+
+ return nullptr;
+ }
+
void DumpState() const;
auto begin() const { return services_.begin(); }
diff --git a/init/sigchld_handler.cpp b/init/sigchld_handler.cpp
index badacaf..0b03324 100644
--- a/init/sigchld_handler.cpp
+++ b/init/sigchld_handler.cpp
@@ -39,9 +39,6 @@
namespace android {
namespace init {
-static int signal_write_fd = -1;
-static int signal_read_fd = -1;
-
static bool ReapOneProcess() {
siginfo_t siginfo = {};
// This returns a zombie pid or informs us that there are no zombies left to be reaped.
@@ -101,46 +98,10 @@
return true;
}
-static void handle_signal() {
- // Clear outstanding requests.
- char buf[32];
- read(signal_read_fd, buf, sizeof(buf));
-
- ReapAnyOutstandingChildren();
-}
-
-static void SIGCHLD_handler(int) {
- if (TEMP_FAILURE_RETRY(write(signal_write_fd, "1", 1)) == -1) {
- PLOG(ERROR) << "write(signal_write_fd) failed";
- }
-}
-
void ReapAnyOutstandingChildren() {
while (ReapOneProcess()) {
}
}
-void sigchld_handler_init() {
- // Create a signalling mechanism for SIGCHLD.
- int s[2];
- if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_NONBLOCK | SOCK_CLOEXEC, 0, s) == -1) {
- PLOG(FATAL) << "socketpair failed in sigchld_handler_init";
- }
-
- signal_write_fd = s[0];
- signal_read_fd = s[1];
-
- // Write to signal_write_fd if we catch SIGCHLD.
- struct sigaction act;
- memset(&act, 0, sizeof(act));
- act.sa_handler = SIGCHLD_handler;
- act.sa_flags = SA_NOCLDSTOP;
- sigaction(SIGCHLD, &act, 0);
-
- ReapAnyOutstandingChildren();
-
- register_epoll_handler(signal_read_fd, handle_signal);
-}
-
} // namespace init
} // namespace android
diff --git a/init/sigchld_handler.h b/init/sigchld_handler.h
index c86dc8d..30063f2 100644
--- a/init/sigchld_handler.h
+++ b/init/sigchld_handler.h
@@ -22,8 +22,6 @@
void ReapAnyOutstandingChildren();
-void sigchld_handler_init(void);
-
} // namespace init
} // namespace android
diff --git a/init/subcontext.cpp b/init/subcontext.cpp
index fdb4641..267d530 100644
--- a/init/subcontext.cpp
+++ b/init/subcontext.cpp
@@ -30,8 +30,6 @@
#include "util.h"
#if defined(__ANDROID__)
-#include <android-base/properties.h>
-
#include "property_service.h"
#include "selinux.h"
#else
@@ -39,7 +37,6 @@
#endif
using android::base::GetExecutablePath;
-using android::base::GetIntProperty;
using android::base::Join;
using android::base::Socketpair;
using android::base::Split;
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/Android.bp b/libbacktrace/Android.bp
index 4bd01d2..4987ba1 100644
--- a/libbacktrace/Android.bp
+++ b/libbacktrace/Android.bp
@@ -22,11 +22,6 @@
"-Werror",
],
- // The latest clang (r230699) does not allow SP/PC to be declared in inline asm lists.
- clang_cflags: ["-Wno-inline-asm"],
-
- include_dirs: ["external/libunwind/include/tdep"],
-
target: {
darwin: {
enabled: false,
@@ -92,12 +87,14 @@
shared_libs: [
"libbase",
"liblog",
- "libunwind",
"libunwindstack",
"libdexfile",
],
- static_libs: ["libcutils"],
+ static_libs: [
+ "libcutils",
+ "libprocinfo",
+ ],
// libdexfile will eventually properly export headers, for now
// include these directly.
@@ -183,12 +180,16 @@
"art/runtime",
],
+ test_suites: ["device-tests"],
data: [
"testdata/arm/*",
"testdata/arm64/*",
"testdata/x86/*",
"testdata/x86_64/*",
],
+ required: [
+ "libbacktrace_test",
+ ],
}
cc_benchmark {
diff --git a/libbacktrace/BacktraceMap.cpp b/libbacktrace/BacktraceMap.cpp
index bdae140..399721d 100644
--- a/libbacktrace/BacktraceMap.cpp
+++ b/libbacktrace/BacktraceMap.cpp
@@ -28,6 +28,9 @@
#include <backtrace/Backtrace.h>
#include <backtrace/BacktraceMap.h>
#include <backtrace/backtrace_constants.h>
+#if defined(__linux__)
+#include <procinfo/process_map.h>
+#endif
#include "thread_utils.h"
@@ -60,27 +63,19 @@
*map = {};
}
-bool BacktraceMap::ParseLine(const char* line, backtrace_map_t* map) {
+#if defined(__APPLE__)
+static bool ParseLine(const char* line, backtrace_map_t* map) {
uint64_t start;
uint64_t end;
char permissions[5];
int name_pos;
-#if defined(__APPLE__)
// Mac OS vmmap(1) output:
// __TEXT 0009f000-000a1000 [ 8K 8K] r-x/rwx SM=COW /Volumes/android/dalvik-dev/out/host/darwin-x86/bin/libcorkscrew_test\n
// 012345678901234567890123456789012345678901234567890123456789
// 0 1 2 3 4 5
if (sscanf(line, "%*21c %" SCNx64 "-%" SCNx64 " [%*13c] %3c/%*3c SM=%*3c %n",
&start, &end, permissions, &name_pos) != 3) {
-#else
-// Linux /proc/<pid>/maps lines:
-// 6f000000-6f01e000 rwxp 00000000 00:0c 16389419 /system/lib/libcomposer.so\n
-// 012345678901234567890123456789012345678901234567890123456789
-// 0 1 2 3 4 5
- if (sscanf(line, "%" SCNx64 "-%" SCNx64 " %4s %*x %*x:%*x %*d %n",
- &start, &end, permissions, &name_pos) != 3) {
-#endif
return false;
}
@@ -107,24 +102,15 @@
map->flags, map->name.c_str());
return true;
}
+#endif // defined(__APPLE__)
bool BacktraceMap::Build() {
#if defined(__APPLE__)
char cmd[sizeof(pid_t)*3 + sizeof("vmmap -w -resident -submap -allSplitLibs -interleaved ") + 1];
-#else
- char path[sizeof(pid_t)*3 + sizeof("/proc//maps") + 1];
-#endif
char line[1024];
-
-#if defined(__APPLE__)
// cmd is guaranteed to always be big enough to hold this string.
snprintf(cmd, sizeof(cmd), "vmmap -w -resident -submap -allSplitLibs -interleaved %d", pid_);
FILE* fp = popen(cmd, "r");
-#else
- // path is guaranteed to always be big enough to hold this string.
- snprintf(path, sizeof(path), "/proc/%d/maps", pid_);
- FILE* fp = fopen(path, "r");
-#endif
if (fp == nullptr) {
return false;
}
@@ -135,13 +121,19 @@
maps_.push_back(map);
}
}
-#if defined(__APPLE__)
pclose(fp);
-#else
- fclose(fp);
-#endif
-
return true;
+#else
+ return android::procinfo::ReadProcessMaps(
+ pid_, [&](uint64_t start, uint64_t end, uint16_t flags, uint64_t, const char* name) {
+ maps_.resize(maps_.size() + 1);
+ backtrace_map_t& map = maps_.back();
+ map.start = start;
+ map.end = end;
+ map.flags = flags;
+ map.name = name;
+ });
+#endif
}
#if defined(__APPLE__)
diff --git a/libbacktrace/include/backtrace/BacktraceMap.h b/libbacktrace/include/backtrace/BacktraceMap.h
index 473d195..a9cfce4 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;
@@ -165,8 +169,6 @@
virtual uint64_t GetLoadBias(size_t /* index */) { return 0; }
- virtual bool ParseLine(const char* line, backtrace_map_t* map);
-
pid_t pid_;
std::deque<backtrace_map_t> maps_;
std::vector<std::string> suffixes_to_ignore_;
diff --git a/libbinderwrapper/Android.bp b/libbinderwrapper/Android.bp
index 6fac0d8..d2487e2 100644
--- a/libbinderwrapper/Android.bp
+++ b/libbinderwrapper/Android.bp
@@ -38,6 +38,7 @@
cc_library_shared {
name: "libbinderwrapper",
defaults: ["libbinderwrapper_defaults"],
+ vendor_available: true,
srcs: [
"binder_wrapper.cc",
diff --git a/libcutils/Android.bp b/libcutils/Android.bp
index bcc9b1c..e823257 100644
--- a/libcutils/Android.bp
+++ b/libcutils/Android.bp
@@ -173,6 +173,7 @@
shared_libs: ["liblog"],
header_libs: [
+ "libbase_headers",
"libcutils_headers",
"libutils_headers",
],
diff --git a/libcutils/ashmem-host.cpp b/libcutils/ashmem-host.cpp
index b2bec99..bb990d5 100644
--- a/libcutils/ashmem-host.cpp
+++ b/libcutils/ashmem-host.cpp
@@ -24,7 +24,6 @@
#include <errno.h>
#include <fcntl.h>
#include <limits.h>
-#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
diff --git a/libcutils/canned_fs_config.cpp b/libcutils/canned_fs_config.cpp
index 6b5763b..2772ef0 100644
--- a/libcutils/canned_fs_config.cpp
+++ b/libcutils/canned_fs_config.cpp
@@ -21,7 +21,6 @@
#include <errno.h>
#include <inttypes.h>
#include <limits.h>
-#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
diff --git a/libcutils/hashmap.cpp b/libcutils/hashmap.cpp
index 65b6ab1..10e3b25 100644
--- a/libcutils/hashmap.cpp
+++ b/libcutils/hashmap.cpp
@@ -21,7 +21,6 @@
#include <cutils/threads.h>
#include <stdlib.h>
#include <string.h>
-#include <stdbool.h>
#include <sys/types.h>
typedef struct Entry Entry;
diff --git a/libcutils/include/cutils/trace.h b/libcutils/include/cutils/trace.h
index bbb150d..58b9f09 100644
--- a/libcutils/include/cutils/trace.h
+++ b/libcutils/include/cutils/trace.h
@@ -74,7 +74,8 @@
#define ATRACE_TAG_ADB (1<<22)
#define ATRACE_TAG_VIBRATOR (1<<23)
#define ATRACE_TAG_AIDL (1<<24)
-#define ATRACE_TAG_LAST ATRACE_TAG_AIDL
+#define ATRACE_TAG_NNAPI (1<<25)
+#define ATRACE_TAG_LAST ATRACE_TAG_NNAPI
// Reserved for initialization.
#define ATRACE_TAG_NOT_READY (1ULL<<63)
diff --git a/libcutils/include/private/android_filesystem_config.h b/libcutils/include/private/android_filesystem_config.h
index 5d17698..3be8ad0 100644
--- a/libcutils/include/private/android_filesystem_config.h
+++ b/libcutils/include/private/android_filesystem_config.h
@@ -129,6 +129,8 @@
#define AID_STATSD 1066 /* statsd daemon */
#define AID_INCIDENTD 1067 /* incidentd daemon */
#define AID_SECURE_ELEMENT 1068 /* secure element subsystem */
+#define AID_LMKD 1069 /* low memory killer daemon */
+#define AID_LLKD 1070 /* live lock daemon */
/* Changes to this file must be made in AOSP, *not* in internal branches. */
#define AID_SHELL 2000 /* adb and debug shell user */
diff --git a/libcutils/sched_policy.cpp b/libcutils/sched_policy.cpp
index f72ec52..3fa548f 100644
--- a/libcutils/sched_policy.cpp
+++ b/libcutils/sched_policy.cpp
@@ -25,6 +25,7 @@
#include <string.h>
#include <unistd.h>
+#include <android-base/macros.h>
#include <log/log.h>
/* Re-map SP_DEFAULT to the system default policy, and leave other values unchanged.
@@ -460,16 +461,16 @@
#endif
-const char *get_sched_policy_name(SchedPolicy policy)
-{
+const char* get_sched_policy_name(SchedPolicy policy) {
policy = _policy(policy);
- static const char* const strings[SP_CNT] = {
+ static const char* const kSchedPolicyNames[] = {
[SP_BACKGROUND] = "bg", [SP_FOREGROUND] = "fg", [SP_SYSTEM] = " ",
[SP_AUDIO_APP] = "aa", [SP_AUDIO_SYS] = "as", [SP_TOP_APP] = "ta",
[SP_RT_APP] = "rt", [SP_RESTRICTED] = "rs",
};
- if ((policy < SP_CNT) && (strings[policy] != NULL))
- return strings[policy];
- else
+ static_assert(arraysize(kSchedPolicyNames) == SP_CNT, "missing name");
+ if (policy < SP_BACKGROUND || policy >= SP_CNT) {
return "error";
+ }
+ return kSchedPolicyNames[policy];
}
diff --git a/libcutils/tests/sched_policy_test.cpp b/libcutils/tests/sched_policy_test.cpp
index 173174a..5942ee5 100644
--- a/libcutils/tests/sched_policy_test.cpp
+++ b/libcutils/tests/sched_policy_test.cpp
@@ -60,6 +60,12 @@
return sleepTimes[median];
}
+static void AssertPolicy(SchedPolicy expected_policy) {
+ SchedPolicy current_policy;
+ ASSERT_EQ(0, get_sched_policy(0, ¤t_policy));
+ EXPECT_EQ(expected_policy, current_policy);
+}
+
TEST(SchedPolicy, set_sched_policy) {
if (!hasCapSysNice()) {
GTEST_LOG_(INFO) << "skipping test that requires CAP_SYS_NICE";
@@ -76,23 +82,17 @@
const unsigned int BG_FG_SLACK_FACTOR = 100;
ASSERT_EQ(0, set_sched_policy(0, SP_BACKGROUND));
+ AssertPolicy(SP_BACKGROUND);
auto bgSleepTime = medianSleepTime();
ASSERT_EQ(0, set_sched_policy(0, SP_FOREGROUND));
+ AssertPolicy(SP_FOREGROUND);
auto fgSleepTime = medianSleepTime();
ASSERT_GT(bgSleepTime, fgSleepTime * BG_FG_SLACK_FACTOR);
}
-TEST(SchedPolicy, get_sched_policy) {
- SchedPolicy policy;
- ASSERT_EQ(0, get_sched_policy(0, &policy));
-
- const char *policyName = get_sched_policy_name(policy);
- EXPECT_NE(nullptr, policyName);
- EXPECT_STRNE("error", policyName);
-
- ASSERT_EQ(0, set_sched_policy(0, SP_BACKGROUND));
- SchedPolicy newPolicy;
- ASSERT_EQ(0, get_sched_policy(0, &newPolicy));
- EXPECT_EQ(SP_BACKGROUND, newPolicy);
+TEST(SchedPolicy, get_sched_policy_name) {
+ EXPECT_STREQ("bg", get_sched_policy_name(SP_BACKGROUND));
+ EXPECT_STREQ("error", get_sched_policy_name(SchedPolicy(-2)));
+ EXPECT_STREQ("error", get_sched_policy_name(SP_CNT));
}
diff --git a/libcutils/trace-dev.inc b/libcutils/trace-dev.inc
index f95c6c5..c9580af 100644
--- a/libcutils/trace-dev.inc
+++ b/libcutils/trace-dev.inc
@@ -24,7 +24,6 @@
#include <limits.h>
#include <pthread.h>
#include <stdatomic.h>
-#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
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/libkeyutils/Android.bp b/libkeyutils/Android.bp
index 0285259..f3593ff 100644
--- a/libkeyutils/Android.bp
+++ b/libkeyutils/Android.bp
@@ -13,4 +13,5 @@
cflags: ["-Werror"],
shared_libs: ["libkeyutils"],
srcs: ["keyutils_test.cpp"],
+ test_suites: ["device-tests"],
}
diff --git a/liblog/include/android/log.h b/liblog/include/android/log.h
index 28c87e4..52cbe8b 100644
--- a/liblog/include/android/log.h
+++ b/liblog/include/android/log.h
@@ -35,6 +35,11 @@
*/
/**
+ * @addtogroup Logging
+ * @{
+ */
+
+/**
* \file
*
* Support routines to send messages to the Android log buffer,
@@ -205,4 +210,6 @@
}
#endif
+/** @} */
+
#endif /* _ANDROID_LOG_H */
diff --git a/libmemunreachable/Android.bp b/libmemunreachable/Android.bp
index f872d0f..248a9d2 100644
--- a/libmemunreachable/Android.bp
+++ b/libmemunreachable/Android.bp
@@ -29,7 +29,6 @@
"HeapWalker.cpp",
"LeakFolding.cpp",
"LeakPipe.cpp",
- "LineBuffer.cpp",
"MemUnreachable.cpp",
"ProcessMappings.cpp",
"PtracerThread.cpp",
@@ -38,6 +37,7 @@
static_libs: [
"libc_malloc_debug_backtrace",
+ "libprocinfo",
],
// Only need this for arm since libc++ uses its own unwind code that
// doesn't mix with the other default unwind code.
@@ -46,6 +46,12 @@
static_libs: ["libunwind_llvm"],
},
},
+
+ // TODO(b/78118944), clang lld link flags do not work with special link
+ // rules for libunwind_llvm yet. Linked aosp_arm-eng image failed to
+ // boot up in the emulator.
+ use_clang_lld: false,
+
export_include_dirs: ["include"],
local_include_dirs: ["include"],
}
@@ -83,6 +89,8 @@
enabled: false,
},
},
+
+ test_suites: ["device-tests"],
}
cc_test {
@@ -97,4 +105,5 @@
"libhwbinder",
"libutils",
],
+ test_suites: ["device-tests"],
}
diff --git a/libmemunreachable/LineBuffer.cpp b/libmemunreachable/LineBuffer.cpp
deleted file mode 100644
index 4ea0542..0000000
--- a/libmemunreachable/LineBuffer.cpp
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * Copyright (C) 2015 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.
- */
-
-// Copied from system/extras/memory_replay/LineBuffer.cpp
-// TODO(ccross): find a way to share between libmemunreachable and memory_replay?
-
-#include <errno.h>
-#include <string.h>
-#include <unistd.h>
-
-#include "LineBuffer.h"
-
-namespace android {
-
-LineBuffer::LineBuffer(int fd, char* buffer, size_t buffer_len)
- : fd_(fd), buffer_(buffer), buffer_len_(buffer_len) {}
-
-bool LineBuffer::GetLine(char** line, size_t* line_len) {
- while (true) {
- if (bytes_ > 0) {
- char* newline = reinterpret_cast<char*>(memchr(buffer_ + start_, '\n', bytes_));
- if (newline != nullptr) {
- *newline = '\0';
- *line = buffer_ + start_;
- start_ = newline - buffer_ + 1;
- bytes_ -= newline - *line + 1;
- *line_len = newline - *line;
- return true;
- }
- }
- if (start_ > 0) {
- // Didn't find anything, copy the current to the front of the buffer.
- memmove(buffer_, buffer_ + start_, bytes_);
- start_ = 0;
- }
- ssize_t bytes = TEMP_FAILURE_RETRY(read(fd_, buffer_ + bytes_, buffer_len_ - bytes_ - 1));
- if (bytes <= 0) {
- if (bytes_ > 0) {
- // The read data might not contain a nul terminator, so add one.
- buffer_[bytes_] = '\0';
- *line = buffer_ + start_;
- *line_len = bytes_;
- bytes_ = 0;
- start_ = 0;
- return true;
- }
- return false;
- }
- bytes_ += bytes;
- }
-}
-
-} // namespace android
diff --git a/libmemunreachable/LineBuffer.h b/libmemunreachable/LineBuffer.h
deleted file mode 100644
index cc6cd0c..0000000
--- a/libmemunreachable/LineBuffer.h
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef _LIBMEMUNREACHABLE_LINE_BUFFER_H
-#define _LIBMEMUNREACHABLE_LINE_BUFFER_H
-
-#include <stdint.h>
-
-namespace android {
-
-class LineBuffer {
- public:
- LineBuffer(int fd, char* buffer, size_t buffer_len);
-
- bool GetLine(char** line, size_t* line_len);
-
- private:
- int fd_;
- char* buffer_ = nullptr;
- size_t buffer_len_ = 0;
- size_t start_ = 0;
- size_t bytes_ = 0;
-};
-
-} // namespace android
-
-#endif // _LIBMEMUNREACHABLE_LINE_BUFFER_H
diff --git a/libmemunreachable/ProcessMappings.cpp b/libmemunreachable/ProcessMappings.cpp
index 9a06870..701ce16 100644
--- a/libmemunreachable/ProcessMappings.cpp
+++ b/libmemunreachable/ProcessMappings.cpp
@@ -14,21 +14,30 @@
* limitations under the License.
*/
+#include <errno.h>
#include <fcntl.h>
#include <inttypes.h>
#include <string.h>
#include <unistd.h>
#include <android-base/unique_fd.h>
+#include <procinfo/process_map.h>
-#include "LineBuffer.h"
#include "ProcessMappings.h"
-#include "log.h"
namespace android {
-// This function is not re-entrant since it uses a static buffer for
-// the line data.
+struct ReadMapCallback {
+ ReadMapCallback(allocator::vector<Mapping>& mappings) : mappings_(mappings) {}
+
+ void operator()(uint64_t start, uint64_t end, uint16_t flags, uint64_t, const char* name) const {
+ mappings_.emplace_back(start, end, flags & PROT_READ, flags & PROT_WRITE, flags & PROT_EXEC,
+ name);
+ }
+
+ allocator::vector<Mapping>& mappings_;
+};
+
bool ProcessMappings(pid_t pid, allocator::vector<Mapping>& mappings) {
char map_buffer[1024];
snprintf(map_buffer, sizeof(map_buffer), "/proc/%d/maps", pid);
@@ -36,35 +45,13 @@
if (fd == -1) {
return false;
}
-
- LineBuffer line_buf(fd, map_buffer, sizeof(map_buffer));
- char* line;
- size_t line_len;
- while (line_buf.GetLine(&line, &line_len)) {
- int name_pos;
- char perms[5];
- Mapping mapping{};
- if (sscanf(line, "%" SCNxPTR "-%" SCNxPTR " %4s %*x %*x:%*x %*d %n", &mapping.begin,
- &mapping.end, perms, &name_pos) == 3) {
- if (perms[0] == 'r') {
- mapping.read = true;
- }
- if (perms[1] == 'w') {
- mapping.write = true;
- }
- if (perms[2] == 'x') {
- mapping.execute = true;
- }
- if (perms[3] == 'p') {
- mapping.priv = true;
- }
- if ((size_t)name_pos < line_len) {
- strlcpy(mapping.name, line + name_pos, sizeof(mapping.name));
- }
- mappings.emplace_back(mapping);
- }
+ allocator::string content(mappings.get_allocator());
+ ssize_t n;
+ while ((n = TEMP_FAILURE_RETRY(read(fd, map_buffer, sizeof(map_buffer)))) > 0) {
+ content.append(map_buffer, n);
}
- return true;
+ ReadMapCallback callback(mappings);
+ return android::procinfo::ReadMapFileContent(&content[0], callback);
}
} // namespace android
diff --git a/libmemunreachable/ProcessMappings.h b/libmemunreachable/ProcessMappings.h
index a0e97e9..94da69b 100644
--- a/libmemunreachable/ProcessMappings.h
+++ b/libmemunreachable/ProcessMappings.h
@@ -17,6 +17,8 @@
#ifndef LIBMEMUNREACHABLE_PROCESS_MAPPING_H_
#define LIBMEMUNREACHABLE_PROCESS_MAPPING_H_
+#include <string.h>
+
#include "Allocator.h"
namespace android {
@@ -27,8 +29,13 @@
bool read;
bool write;
bool execute;
- bool priv;
char name[96];
+
+ Mapping() {}
+ Mapping(uintptr_t begin, uintptr_t end, bool read, bool write, bool execute, const char* name)
+ : begin(begin), end(end), read(read), write(write), execute(execute) {
+ strlcpy(this->name, name, sizeof(this->name));
+ }
};
// This function is not re-entrant since it uses a static buffer for
diff --git a/libmemunreachable/README.md b/libmemunreachable/README.md
index ae8fa94..6d9141a 100644
--- a/libmemunreachable/README.md
+++ b/libmemunreachable/README.md
@@ -12,6 +12,27 @@
Usage
-------
+### In Android apps ###
+
+libmemunreachble is loaded by zygote and can be triggered with `dumpsys -t 600 meminfo --unreachable [process]`.
+
+To enable malloc\_debug backtraces on allocations for a single app process on a userdebug device, use:
+```
+adb root
+adb shell setprop libc.debug.malloc.program app_process
+adb shell setprop wrap.[process] "\$\@"
+adb shell setprop libc.debug.malloc.options backtrace=4
+```
+
+Kill and restart the app, trigger the leak, and then run `dumpsys -t 600 meminfo --unreachable [process]`.
+
+To disable malloc\_debug:
+```
+adb shell setprop libc.debug.malloc.options "''"
+adb shell setprop libc.debug.malloc.program "''"
+adb shell setprop wrap.[process] "''"
+```
+
### C interface ###
#### `bool LogUnreachableMemory(bool log_contents, size_t limit)` ####
diff --git a/libprocinfo/Android.bp b/libprocinfo/Android.bp
index 83b0a7f..d776b3d 100644
--- a/libprocinfo/Android.bp
+++ b/libprocinfo/Android.bp
@@ -59,6 +59,7 @@
host_supported: true,
srcs: [
"process_test.cpp",
+ "process_map_test.cpp",
],
target: {
darwin: {
@@ -83,4 +84,37 @@
suffix: "64",
},
},
+
+ data: [
+ "testdata/*",
+ ],
+
+ test_suites: ["device-tests"],
+}
+
+cc_benchmark {
+ name: "libprocinfo_benchmark",
+ defaults: ["libprocinfo_defaults"],
+ srcs: [
+ "process_map_benchmark.cpp",
+ ],
+ shared_libs: [
+ "libbacktrace",
+ "libbase",
+ "libprocinfo",
+ "libunwindstack",
+ ],
+ compile_multilib: "both",
+ multilib: {
+ lib32: {
+ suffix: "32",
+ },
+ lib64: {
+ suffix: "64",
+ },
+ },
+
+ data: [
+ "testdata/*",
+ ],
}
diff --git a/libprocinfo/include/procinfo/process_map.h b/libprocinfo/include/procinfo/process_map.h
new file mode 100644
index 0000000..3771f9f
--- /dev/null
+++ b/libprocinfo/include/procinfo/process_map.h
@@ -0,0 +1,151 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <stdlib.h>
+#include <sys/mman.h>
+#include <sys/types.h>
+
+#include <functional>
+#include <string>
+
+#include <android-base/file.h>
+
+namespace android {
+namespace procinfo {
+
+template <class CallbackType>
+bool ReadMapFileContent(char* content, const CallbackType& callback) {
+ uint64_t start_addr;
+ uint64_t end_addr;
+ uint16_t flags;
+ uint64_t pgoff;
+ char* next_line = content;
+ char* p;
+
+ auto pass_space = [&]() {
+ if (*p != ' ') {
+ return false;
+ }
+ while (*p == ' ') {
+ p++;
+ }
+ return true;
+ };
+
+ auto pass_xdigit = [&]() {
+ if (!isxdigit(*p)) {
+ return false;
+ }
+ do {
+ p++;
+ } while (isxdigit(*p));
+ return true;
+ };
+
+ while (next_line != nullptr && *next_line != '\0') {
+ p = next_line;
+ next_line = strchr(next_line, '\n');
+ if (next_line != nullptr) {
+ *next_line = '\0';
+ next_line++;
+ }
+ // Parse line like: 00400000-00409000 r-xp 00000000 fc:00 426998 /usr/lib/gvfs/gvfsd-http
+ char* end;
+ // start_addr
+ start_addr = strtoull(p, &end, 16);
+ if (end == p || *end != '-') {
+ return false;
+ }
+ p = end + 1;
+ // end_addr
+ end_addr = strtoull(p, &end, 16);
+ if (end == p) {
+ return false;
+ }
+ p = end;
+ if (!pass_space()) {
+ return false;
+ }
+ // flags
+ flags = 0;
+ if (*p == 'r') {
+ flags |= PROT_READ;
+ } else if (*p != '-') {
+ return false;
+ }
+ p++;
+ if (*p == 'w') {
+ flags |= PROT_WRITE;
+ } else if (*p != '-') {
+ return false;
+ }
+ p++;
+ if (*p == 'x') {
+ flags |= PROT_EXEC;
+ } else if (*p != '-') {
+ return false;
+ }
+ p++;
+ if (*p != 'p' && *p != 's') {
+ return false;
+ }
+ p++;
+ if (!pass_space()) {
+ return false;
+ }
+ // pgoff
+ pgoff = strtoull(p, &end, 16);
+ if (end == p) {
+ return false;
+ }
+ p = end;
+ if (!pass_space()) {
+ return false;
+ }
+ // major:minor
+ if (!pass_xdigit() || *p++ != ':' || !pass_xdigit() || !pass_space()) {
+ return false;
+ }
+ // inode
+ if (!pass_xdigit() || (*p != '\0' && !pass_space())) {
+ return false;
+ }
+ // filename
+ callback(start_addr, end_addr, flags, pgoff, p);
+ }
+ return true;
+}
+
+inline bool ReadMapFile(
+ const std::string& map_file,
+ const std::function<void(uint64_t, uint64_t, uint16_t, uint64_t, const char*)>& callback) {
+ std::string content;
+ if (!android::base::ReadFileToString(map_file, &content)) {
+ return false;
+ }
+ return ReadMapFileContent(&content[0], callback);
+}
+
+inline bool ReadProcessMaps(
+ pid_t pid,
+ const std::function<void(uint64_t, uint64_t, uint16_t, uint64_t, const char*)>& callback) {
+ return ReadMapFile("/proc/" + std::to_string(pid) + "/maps", callback);
+}
+
+} /* namespace procinfo */
+} /* namespace android */
diff --git a/libprocinfo/process_map_benchmark.cpp b/libprocinfo/process_map_benchmark.cpp
new file mode 100644
index 0000000..d9e8a4d
--- /dev/null
+++ b/libprocinfo/process_map_benchmark.cpp
@@ -0,0 +1,85 @@
+/*
+ * 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 <procinfo/process_map.h>
+
+#include <string.h>
+
+#include <string>
+
+#include <android-base/file.h>
+#include <android-base/logging.h>
+#include <backtrace/BacktraceMap.h>
+#include <unwindstack/Maps.h>
+
+#include <benchmark/benchmark.h>
+
+struct MapInfo {
+ uint64_t start;
+ uint64_t end;
+ uint16_t flags;
+ uint64_t pgoff;
+ const std::string name;
+
+ MapInfo(uint64_t start, uint64_t end, uint16_t flags, uint64_t pgoff, const char* name)
+ : start(start), end(end), flags(flags), pgoff(pgoff), name(name) {}
+};
+
+static void BM_ReadMapFile(benchmark::State& state) {
+ std::string map_file = android::base::GetExecutableDirectory() + "/testdata/maps";
+ for (auto _ : state) {
+ std::vector<MapInfo> maps;
+ android::procinfo::ReadMapFile(
+ map_file, [&](uint64_t start, uint64_t end, uint16_t flags, uint64_t pgoff,
+ const char* name) { maps.emplace_back(start, end, flags, pgoff, name); });
+ CHECK_EQ(maps.size(), 2043u);
+ }
+}
+BENCHMARK(BM_ReadMapFile);
+
+static void BM_unwindstack_FileMaps(benchmark::State& state) {
+ std::string map_file = android::base::GetExecutableDirectory() + "/testdata/maps";
+ for (auto _ : state) {
+ unwindstack::FileMaps maps(map_file);
+ maps.Parse();
+ CHECK_EQ(maps.Total(), 2043u);
+ }
+}
+BENCHMARK(BM_unwindstack_FileMaps);
+
+static void BM_unwindstack_BufferMaps(benchmark::State& state) {
+ std::string map_file = android::base::GetExecutableDirectory() + "/testdata/maps";
+ std::string content;
+ CHECK(android::base::ReadFileToString(map_file, &content));
+ for (auto _ : state) {
+ unwindstack::BufferMaps maps(content.c_str());
+ maps.Parse();
+ CHECK_EQ(maps.Total(), 2043u);
+ }
+}
+BENCHMARK(BM_unwindstack_BufferMaps);
+
+static void BM_backtrace_BacktraceMap(benchmark::State& state) {
+ pid_t pid = getpid();
+ for (auto _ : state) {
+ BacktraceMap* map = BacktraceMap::Create(pid, true);
+ CHECK(map != nullptr);
+ delete map;
+ }
+}
+BENCHMARK(BM_backtrace_BacktraceMap);
+
+BENCHMARK_MAIN();
diff --git a/libprocinfo/process_map_test.cpp b/libprocinfo/process_map_test.cpp
new file mode 100644
index 0000000..900fd85
--- /dev/null
+++ b/libprocinfo/process_map_test.cpp
@@ -0,0 +1,60 @@
+/*
+ * 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 <procinfo/process_map.h>
+
+#include <string>
+
+#include <android-base/file.h>
+
+#include <gtest/gtest.h>
+
+struct MapInfo {
+ uint64_t start;
+ uint64_t end;
+ uint16_t flags;
+ uint64_t pgoff;
+ const std::string name;
+
+ MapInfo(uint64_t start, uint64_t end, uint16_t flags, uint64_t pgoff, const char* name)
+ : start(start), end(end), flags(flags), pgoff(pgoff), name(name) {}
+};
+
+TEST(process_map, smoke) {
+ std::string map_file = android::base::GetExecutableDirectory() + "/testdata/maps";
+ std::vector<MapInfo> maps;
+ ASSERT_TRUE(android::procinfo::ReadMapFile(
+ map_file, [&](uint64_t start, uint64_t end, uint16_t flags, uint64_t pgoff,
+ const char* name) { maps.emplace_back(start, end, flags, pgoff, name); }));
+ ASSERT_EQ(2043u, maps.size());
+ ASSERT_EQ(maps[0].start, 0x12c00000ULL);
+ ASSERT_EQ(maps[0].end, 0x2ac00000ULL);
+ ASSERT_EQ(maps[0].flags, PROT_READ | PROT_WRITE);
+ ASSERT_EQ(maps[0].pgoff, 0ULL);
+ ASSERT_EQ(maps[0].name, "/dev/ashmem/dalvik-main space (region space) (deleted)");
+ ASSERT_EQ(maps[876].start, 0x70e6c4f000ULL);
+ ASSERT_EQ(maps[876].end, 0x70e6c6b000ULL);
+ ASSERT_EQ(maps[876].flags, PROT_READ | PROT_EXEC);
+ ASSERT_EQ(maps[876].pgoff, 0ULL);
+ ASSERT_EQ(maps[876].name, "/system/lib64/libutils.so");
+ ASSERT_EQ(maps[1260].start, 0x70e96fa000ULL);
+ ASSERT_EQ(maps[1260].end, 0x70e96fb000ULL);
+ ASSERT_EQ(maps[1260].flags, PROT_READ);
+ ASSERT_EQ(maps[1260].pgoff, 0ULL);
+ ASSERT_EQ(maps[1260].name,
+ "/dev/ashmem/dalvik-classes.dex extracted in memory from "
+ "/data/app/com.google.sample.tunnel-HGGRU03Gu1Mwkf_-RnFmvw==/base.apk (deleted)");
+}
diff --git a/libprocinfo/testdata/maps b/libprocinfo/testdata/maps
new file mode 100644
index 0000000..3b312e3
--- /dev/null
+++ b/libprocinfo/testdata/maps
@@ -0,0 +1,2043 @@
+12c00000-2ac00000 rw-p 00000000 00:05 10267643 /dev/ashmem/dalvik-main space (region space) (deleted)
+6fb5d000-6fd6e000 rw-p 00000000 103:1d 639511 /data/dalvik-cache/arm64/system@framework@boot.art
+6fd6e000-6fd82000 r--p 00211000 103:1d 639511 /data/dalvik-cache/arm64/system@framework@boot.art
+6fd82000-6fe47000 rw-p 00000000 103:1d 639514 /data/dalvik-cache/arm64/system@framework@boot-core-libart.art
+6fe47000-6fe52000 r--p 000c5000 103:1d 639514 /data/dalvik-cache/arm64/system@framework@boot-core-libart.art
+6fe52000-6fe84000 rw-p 00000000 103:1d 639517 /data/dalvik-cache/arm64/system@framework@boot-conscrypt.art
+6fe84000-6fe87000 r--p 00032000 103:1d 639517 /data/dalvik-cache/arm64/system@framework@boot-conscrypt.art
+6fe87000-6feb2000 rw-p 00000000 103:1d 639520 /data/dalvik-cache/arm64/system@framework@boot-okhttp.art
+6feb2000-6feb5000 r--p 0002b000 103:1d 639520 /data/dalvik-cache/arm64/system@framework@boot-okhttp.art
+6feb5000-6fef4000 rw-p 00000000 103:1d 639523 /data/dalvik-cache/arm64/system@framework@boot-bouncycastle.art
+6fef4000-6fefb000 r--p 0003f000 103:1d 639523 /data/dalvik-cache/arm64/system@framework@boot-bouncycastle.art
+6fefb000-6ff3f000 rw-p 00000000 103:1d 639526 /data/dalvik-cache/arm64/system@framework@boot-apache-xml.art
+6ff3f000-6ff45000 r--p 00044000 103:1d 639526 /data/dalvik-cache/arm64/system@framework@boot-apache-xml.art
+6ff45000-6ff7a000 rw-p 00000000 103:1d 639529 /data/dalvik-cache/arm64/system@framework@boot-ext.art
+6ff7a000-6ff85000 r--p 00035000 103:1d 639529 /data/dalvik-cache/arm64/system@framework@boot-ext.art
+6ff85000-70594000 rw-p 00000000 103:1d 639532 /data/dalvik-cache/arm64/system@framework@boot-framework.art
+70594000-705cb000 r--p 0060f000 103:1d 639532 /data/dalvik-cache/arm64/system@framework@boot-framework.art
+705cb000-7061f000 rw-p 00000000 103:1d 639535 /data/dalvik-cache/arm64/system@framework@boot-telephony-common.art
+7061f000-70629000 r--p 00054000 103:1d 639535 /data/dalvik-cache/arm64/system@framework@boot-telephony-common.art
+70629000-70635000 rw-p 00000000 103:1d 639538 /data/dalvik-cache/arm64/system@framework@boot-voip-common.art
+70635000-70636000 r--p 0000c000 103:1d 639538 /data/dalvik-cache/arm64/system@framework@boot-voip-common.art
+70636000-70644000 rw-p 00000000 103:1d 639541 /data/dalvik-cache/arm64/system@framework@boot-ims-common.art
+70644000-70645000 r--p 0000e000 103:1d 639541 /data/dalvik-cache/arm64/system@framework@boot-ims-common.art
+70645000-70648000 rw-p 00000000 103:1d 639544 /data/dalvik-cache/arm64/system@framework@boot-android.hidl.base-V1.0-java.art
+70648000-7064c000 rw-p 00000000 103:1d 639547 /data/dalvik-cache/arm64/system@framework@boot-android.hidl.manager-V1.0-java.art
+7064c000-7064d000 r--p 00004000 103:1d 639547 /data/dalvik-cache/arm64/system@framework@boot-android.hidl.manager-V1.0-java.art
+7064d000-7064e000 rw-p 00000000 103:1d 639550 /data/dalvik-cache/arm64/system@framework@boot-framework-oahl-backward-compatibility.art
+7064e000-70652000 rw-p 00000000 103:1d 639553 /data/dalvik-cache/arm64/system@framework@boot-android.test.base.art
+70652000-70653000 r--p 00004000 103:1d 639553 /data/dalvik-cache/arm64/system@framework@boot-android.test.base.art
+70653000-70654000 rw-p 00000000 103:1d 639556 /data/dalvik-cache/arm64/system@framework@boot-com.google.vr.platform.art
+70654000-70655000 r--p 00001000 103:1d 639556 /data/dalvik-cache/arm64/system@framework@boot-com.google.vr.platform.art
+70655000-70731000 r--p 00000000 fc:00 940 /system/framework/arm64/boot.oat
+70731000-709ca000 r-xp 000dc000 fc:00 940 /system/framework/arm64/boot.oat
+709ca000-709cb000 rw-p 00000000 00:00 0 [anon:.bss]
+709cb000-70e4c000 r--s 00000000 fc:00 961 /system/framework/boot.vdex
+70e4c000-70e4d000 r--p 00375000 fc:00 940 /system/framework/arm64/boot.oat
+70e4d000-70e4e000 rw-p 00376000 fc:00 940 /system/framework/arm64/boot.oat
+70e4e000-70eab000 r--p 00000000 fc:00 916 /system/framework/arm64/boot-core-libart.oat
+70eab000-70fad000 r-xp 0005d000 fc:00 916 /system/framework/arm64/boot-core-libart.oat
+70fad000-70fae000 rw-p 00000000 00:00 0 [anon:.bss]
+70fae000-712a9000 r--s 00000000 fc:00 702 /system/framework/boot-core-libart.vdex
+712a9000-712aa000 r--p 0015f000 fc:00 916 /system/framework/arm64/boot-core-libart.oat
+712aa000-712ab000 rw-p 00160000 fc:00 916 /system/framework/arm64/boot-core-libart.oat
+712ab000-712bb000 r--p 00000000 fc:00 941 /system/framework/arm64/boot-conscrypt.oat
+712bb000-712e4000 r-xp 00010000 fc:00 941 /system/framework/arm64/boot-conscrypt.oat
+712e4000-712e5000 rw-p 00000000 00:00 0 [anon:.bss]
+712e5000-71346000 r--s 00000000 fc:00 970 /system/framework/boot-conscrypt.vdex
+71346000-71347000 r--p 00039000 fc:00 941 /system/framework/arm64/boot-conscrypt.oat
+71347000-71348000 rw-p 0003a000 fc:00 941 /system/framework/arm64/boot-conscrypt.oat
+71348000-71361000 r--p 00000000 fc:00 908 /system/framework/arm64/boot-okhttp.oat
+71361000-713a3000 r-xp 00019000 fc:00 908 /system/framework/arm64/boot-okhttp.oat
+713a3000-713a4000 rw-p 00000000 00:00 0 [anon:.bss]
+713a4000-71403000 r--s 00000000 fc:00 886 /system/framework/boot-okhttp.vdex
+71403000-71404000 r--p 0005b000 fc:00 908 /system/framework/arm64/boot-okhttp.oat
+71404000-71405000 rw-p 0005c000 fc:00 908 /system/framework/arm64/boot-okhttp.oat
+71405000-71415000 r--p 00000000 fc:00 936 /system/framework/arm64/boot-bouncycastle.oat
+71415000-71437000 r-xp 00010000 fc:00 936 /system/framework/arm64/boot-bouncycastle.oat
+71437000-71438000 rw-p 00000000 00:00 0 [anon:.bss]
+71438000-7157b000 r--s 00000000 fc:00 1006 /system/framework/boot-bouncycastle.vdex
+7157b000-7157c000 r--p 00032000 fc:00 936 /system/framework/arm64/boot-bouncycastle.oat
+7157c000-7157d000 rw-p 00033000 fc:00 936 /system/framework/arm64/boot-bouncycastle.oat
+7157d000-71583000 r--p 00000000 fc:00 932 /system/framework/arm64/boot-apache-xml.oat
+71583000-71584000 r-xp 00006000 fc:00 932 /system/framework/arm64/boot-apache-xml.oat
+71584000-716a7000 r--s 00000000 fc:00 883 /system/framework/boot-apache-xml.vdex
+716a7000-716a8000 r--p 00007000 fc:00 932 /system/framework/arm64/boot-apache-xml.oat
+716a8000-716a9000 rw-p 00008000 fc:00 932 /system/framework/arm64/boot-apache-xml.oat
+716a9000-716b5000 r--p 00000000 fc:00 891 /system/framework/arm64/boot-ext.oat
+716b5000-716cc000 r-xp 0000c000 fc:00 891 /system/framework/arm64/boot-ext.oat
+716cc000-716cd000 rw-p 00000000 00:00 0 [anon:.bss]
+716cd000-717b8000 r--s 00000000 fc:00 879 /system/framework/boot-ext.vdex
+717b8000-717b9000 r--p 00023000 fc:00 891 /system/framework/arm64/boot-ext.oat
+717b9000-717ba000 rw-p 00024000 fc:00 891 /system/framework/arm64/boot-ext.oat
+717ba000-71aeb000 r--p 00000000 fc:00 943 /system/framework/arm64/boot-framework.oat
+71aeb000-72390000 r-xp 00331000 fc:00 943 /system/framework/arm64/boot-framework.oat
+72390000-72396000 rw-p 00000000 00:00 0 [anon:.bss]
+72396000-73746000 r--s 00000000 fc:00 985 /system/framework/boot-framework.vdex
+73746000-73747000 r--p 00bd6000 fc:00 943 /system/framework/arm64/boot-framework.oat
+73747000-73748000 rw-p 00bd7000 fc:00 943 /system/framework/arm64/boot-framework.oat
+73748000-73780000 r--p 00000000 fc:00 893 /system/framework/arm64/boot-telephony-common.oat
+73780000-73818000 r-xp 00038000 fc:00 893 /system/framework/arm64/boot-telephony-common.oat
+73818000-7381a000 rw-p 00000000 00:00 0 [anon:.bss]
+7381a000-73af0000 r--s 00000000 fc:00 697 /system/framework/boot-telephony-common.vdex
+73af0000-73af1000 r--p 000d0000 fc:00 893 /system/framework/arm64/boot-telephony-common.oat
+73af1000-73af2000 rw-p 000d1000 fc:00 893 /system/framework/arm64/boot-telephony-common.oat
+73af2000-73af6000 r--p 00000000 fc:00 922 /system/framework/arm64/boot-voip-common.oat
+73af6000-73af8000 r-xp 00004000 fc:00 922 /system/framework/arm64/boot-voip-common.oat
+73af8000-73af9000 rw-p 00000000 00:00 0 [anon:.bss]
+73af9000-73b1e000 r--s 00000000 fc:00 959 /system/framework/boot-voip-common.vdex
+73b1e000-73b1f000 r--p 00006000 fc:00 922 /system/framework/arm64/boot-voip-common.oat
+73b1f000-73b20000 rw-p 00007000 fc:00 922 /system/framework/arm64/boot-voip-common.oat
+73b20000-73b23000 r--p 00000000 fc:00 918 /system/framework/arm64/boot-ims-common.oat
+73b23000-73b25000 r-xp 00003000 fc:00 918 /system/framework/arm64/boot-ims-common.oat
+73b25000-73b26000 rw-p 00000000 00:00 0 [anon:.bss]
+73b26000-73b48000 r--s 00000000 fc:00 957 /system/framework/boot-ims-common.vdex
+73b48000-73b49000 r--p 00005000 fc:00 918 /system/framework/arm64/boot-ims-common.oat
+73b49000-73b4a000 rw-p 00006000 fc:00 918 /system/framework/arm64/boot-ims-common.oat
+73b4a000-73b4d000 r--p 00000000 fc:00 909 /system/framework/arm64/boot-android.hidl.base-V1.0-java.oat
+73b4d000-73b4e000 r-xp 00003000 fc:00 909 /system/framework/arm64/boot-android.hidl.base-V1.0-java.oat
+73b4e000-73b55000 r--s 00000000 fc:00 972 /system/framework/boot-android.hidl.base-V1.0-java.vdex
+73b55000-73b56000 r--p 00004000 fc:00 909 /system/framework/arm64/boot-android.hidl.base-V1.0-java.oat
+73b56000-73b57000 rw-p 00005000 fc:00 909 /system/framework/arm64/boot-android.hidl.base-V1.0-java.oat
+73b57000-73b5a000 r--p 00000000 fc:00 954 /system/framework/arm64/boot-android.hidl.manager-V1.0-java.oat
+73b5a000-73b5c000 r-xp 00003000 fc:00 954 /system/framework/arm64/boot-android.hidl.manager-V1.0-java.oat
+73b5c000-73b5d000 rw-p 00000000 00:00 0 [anon:.bss]
+73b5d000-73b68000 r--s 00000000 fc:00 704 /system/framework/boot-android.hidl.manager-V1.0-java.vdex
+73b68000-73b69000 r--p 00005000 fc:00 954 /system/framework/arm64/boot-android.hidl.manager-V1.0-java.oat
+73b69000-73b6a000 rw-p 00006000 fc:00 954 /system/framework/arm64/boot-android.hidl.manager-V1.0-java.oat
+73b6a000-73b6d000 r--p 00000000 fc:00 904 /system/framework/arm64/boot-framework-oahl-backward-compatibility.oat
+73b6d000-73b6e000 r-xp 00003000 fc:00 904 /system/framework/arm64/boot-framework-oahl-backward-compatibility.oat
+73b6e000-73b6f000 r--s 00000000 fc:00 994 /system/framework/boot-framework-oahl-backward-compatibility.vdex
+73b6f000-73b70000 r--p 00004000 fc:00 904 /system/framework/arm64/boot-framework-oahl-backward-compatibility.oat
+73b70000-73b71000 rw-p 00005000 fc:00 904 /system/framework/arm64/boot-framework-oahl-backward-compatibility.oat
+73b71000-73b75000 r--p 00000000 fc:00 896 /system/framework/arm64/boot-android.test.base.oat
+73b75000-73b79000 r-xp 00004000 fc:00 896 /system/framework/arm64/boot-android.test.base.oat
+73b79000-73b7a000 rw-p 00000000 00:00 0 [anon:.bss]
+73b7a000-73b82000 r--s 00000000 fc:00 706 /system/framework/boot-android.test.base.vdex
+73b82000-73b83000 r--p 00008000 fc:00 896 /system/framework/arm64/boot-android.test.base.oat
+73b83000-73b84000 rw-p 00009000 fc:00 896 /system/framework/arm64/boot-android.test.base.oat
+73b84000-73b87000 r--p 00000000 fc:00 899 /system/framework/arm64/boot-com.google.vr.platform.oat
+73b87000-73b88000 r-xp 00003000 fc:00 899 /system/framework/arm64/boot-com.google.vr.platform.oat
+73b88000-73b89000 r--s 00000000 fc:00 884 /system/framework/boot-com.google.vr.platform.vdex
+73b89000-73b8a000 r--p 00004000 fc:00 899 /system/framework/arm64/boot-com.google.vr.platform.oat
+73b8a000-73b8b000 rw-p 00005000 fc:00 899 /system/framework/arm64/boot-com.google.vr.platform.oat
+73b8b000-73b93000 rw-p 00000000 00:05 10267640 /dev/ashmem/dalvik-non moving space (deleted)
+73b93000-77b8b000 ---p 00008000 00:05 10267640 /dev/ashmem/dalvik-non moving space (deleted)
+77b8b000-97b8b000 rw-p 00000000 00:05 10267645 /dev/ashmem/dalvik-free list large object space (deleted)
+97b8b000-99b8b000 rw-p 00000000 00:05 10270989 /dev/ashmem/dalvik-data-code-cache (deleted)
+99b8b000-9bb8b000 r-xp 00000000 00:05 10270990 /dev/ashmem/dalvik-jit-code-cache (deleted)
+ebad6000-ebad7000 ---p 00000000 00:05 10269717 /dev/ashmem/dalvik-Sentinel fault page (deleted)
+7ffb6e000-7ffb76000 rw-s 000e5000 00:10 20630 /dev/kgsl-3d0
+7ffb76000-7ffb78000 rw-s 000e0000 00:10 20630 /dev/kgsl-3d0
+7ffbc3000-7ffbc4000 rw-s 000e8000 00:10 20630 /dev/kgsl-3d0
+7ffbc4000-7ffbc5000 rw-s 000e7000 00:10 20630 /dev/kgsl-3d0
+7ffbc6000-7ffbce000 rw-s 000e4000 00:10 20630 /dev/kgsl-3d0
+7ffbd0000-7ffbd2000 rw-s 000df000 00:10 20630 /dev/kgsl-3d0
+7ffbd2000-7ffbd4000 rw-s 000de000 00:10 20630 /dev/kgsl-3d0
+7ffbd4000-7ffbd6000 rw-s 000dd000 00:10 20630 /dev/kgsl-3d0
+7ffbd6000-7ffbd8000 rw-s 000dc000 00:10 20630 /dev/kgsl-3d0
+7ffbd8000-7ffbda000 rw-s 000db000 00:10 20630 /dev/kgsl-3d0
+7ffbda000-7ffbdc000 rw-s 000da000 00:10 20630 /dev/kgsl-3d0
+7ffbdd000-7ffbde000 rw-s 000ec000 00:10 20630 /dev/kgsl-3d0
+7ffbde000-7ffbe0000 rw-s 000d8000 00:10 20630 /dev/kgsl-3d0
+7ffce1000-7ffce2000 rw-s 000e6000 00:10 20630 /dev/kgsl-3d0
+7ffce2000-7ffce4000 rw-s 000d9000 00:10 20630 /dev/kgsl-3d0
+7ffce4000-7ffce8000 rw-s 000d4000 00:10 20630 /dev/kgsl-3d0
+7ffce8000-7ffcf8000 rw-s 000d2000 00:10 20630 /dev/kgsl-3d0
+7ffcf8000-7ffd08000 rw-s 000d1000 00:10 20630 /dev/kgsl-3d0
+7ffd08000-7ffd10000 rw-s 000d0000 00:10 20630 /dev/kgsl-3d0
+7ffd14000-7ffd18000 rw-s 000cd000 00:10 20630 /dev/kgsl-3d0
+7ffd18000-7ffd28000 rw-s 000cc000 00:10 20630 /dev/kgsl-3d0
+7ffd28000-7ffd38000 rw-s 000cb000 00:10 20630 /dev/kgsl-3d0
+7ffd38000-7ffd48000 rw-s 000ca000 00:10 20630 /dev/kgsl-3d0
+7ffd48000-7ffd58000 rw-s 000c9000 00:10 20630 /dev/kgsl-3d0
+7ffd58000-7ffd68000 rw-s 000c8000 00:10 20630 /dev/kgsl-3d0
+7ffd68000-7ffd6c000 rw-s 000c7000 00:10 20630 /dev/kgsl-3d0
+7ffdb1000-7ffdb2000 rw-s 000e3000 00:10 20630 /dev/kgsl-3d0
+7ffdb4000-7ffdb5000 rw-s 000e2000 00:10 20630 /dev/kgsl-3d0
+7ffdb5000-7ffdb7000 rw-s 000d7000 00:10 20630 /dev/kgsl-3d0
+7ffdb7000-7ffdb8000 rw-s 000c2000 00:10 20630 /dev/kgsl-3d0
+7ffdb8000-7ffdbc000 rw-s 000c0000 00:10 20630 /dev/kgsl-3d0
+7ffdbc000-7ffdc0000 rw-s 000be000 00:10 20630 /dev/kgsl-3d0
+7ffdc0000-7ffe00000 rw-s 000bb000 00:10 20630 /dev/kgsl-3d0
+7ffe00000-7ffe20000 rw-s 000ba000 00:10 20630 /dev/kgsl-3d0
+7ffe20000-7ffee0000 rw-s 000b9000 00:10 20630 /dev/kgsl-3d0
+7ffee1000-7ffee3000 rw-s 000c1000 00:10 20630 /dev/kgsl-3d0
+7ffee3000-7ffee4000 rw-s 000bf000 00:10 20630 /dev/kgsl-3d0
+7ffee4000-7ffee8000 rw-s 000bd000 00:10 20630 /dev/kgsl-3d0
+7ffee8000-7ffee9000 rw-s 000bc000 00:10 20630 /dev/kgsl-3d0
+7ffeea000-7ffeeb000 rw-s 000e1000 00:10 20630 /dev/kgsl-3d0
+7ffeeb000-7ffeec000 rw-s 000b6000 00:10 20630 /dev/kgsl-3d0
+7ffeec000-7ffeed000 rw-s 000b5000 00:10 20630 /dev/kgsl-3d0
+7ffeed000-7ffeee000 rw-s 000b4000 00:10 20630 /dev/kgsl-3d0
+7ffeee000-7ffeef000 rw-s 000b3000 00:10 20630 /dev/kgsl-3d0
+7ffeef000-7ffef0000 rw-s 000b2000 00:10 20630 /dev/kgsl-3d0
+7ffef0000-7ffef1000 rw-s 000b1000 00:10 20630 /dev/kgsl-3d0
+7ffef1000-7ffef2000 rw-s 000b0000 00:10 20630 /dev/kgsl-3d0
+7ffef2000-7ffef3000 rw-s 000af000 00:10 20630 /dev/kgsl-3d0
+7ffef3000-7ffef4000 rw-s 000ae000 00:10 20630 /dev/kgsl-3d0
+7ffef4000-7ffef5000 rw-s 000ad000 00:10 20630 /dev/kgsl-3d0
+7ffef5000-7ffef6000 rw-s 000ac000 00:10 20630 /dev/kgsl-3d0
+7ffef6000-7ffef7000 rw-s 000ab000 00:10 20630 /dev/kgsl-3d0
+7ffef7000-7ffef8000 rw-s 000aa000 00:10 20630 /dev/kgsl-3d0
+7ffef8000-7ffef9000 rw-s 000a9000 00:10 20630 /dev/kgsl-3d0
+7ffef9000-7ffefa000 rw-s 000a8000 00:10 20630 /dev/kgsl-3d0
+7ffefa000-7ffefb000 rw-s 000a7000 00:10 20630 /dev/kgsl-3d0
+7ffefb000-7ffefc000 rw-s 000a6000 00:10 20630 /dev/kgsl-3d0
+7ffefc000-7ffefd000 rw-s 000a5000 00:10 20630 /dev/kgsl-3d0
+7ffefd000-7ffefe000 rw-s 000a4000 00:10 20630 /dev/kgsl-3d0
+7ffefe000-7ffeff000 rw-s 000a3000 00:10 20630 /dev/kgsl-3d0
+7ffeff000-7fff00000 rw-s 000a2000 00:10 20630 /dev/kgsl-3d0
+7fff00000-7fff01000 rw-s 000a1000 00:10 20630 /dev/kgsl-3d0
+7fff01000-7fff02000 rw-s 000a0000 00:10 20630 /dev/kgsl-3d0
+7fff02000-7fff03000 rw-s 0009f000 00:10 20630 /dev/kgsl-3d0
+7fff03000-7fff04000 rw-s 0009e000 00:10 20630 /dev/kgsl-3d0
+7fff04000-7fff05000 rw-s 0009d000 00:10 20630 /dev/kgsl-3d0
+7fff05000-7fff06000 rw-s 0009c000 00:10 20630 /dev/kgsl-3d0
+7fff06000-7fff07000 rw-s 0009b000 00:10 20630 /dev/kgsl-3d0
+7fff07000-7fff08000 rw-s 0009a000 00:10 20630 /dev/kgsl-3d0
+7fff08000-7fff09000 rw-s 00099000 00:10 20630 /dev/kgsl-3d0
+7fff09000-7fff0a000 rw-s 00098000 00:10 20630 /dev/kgsl-3d0
+7fff0a000-7fff0b000 rw-s 00097000 00:10 20630 /dev/kgsl-3d0
+7fff0b000-7fff0c000 rw-s 00096000 00:10 20630 /dev/kgsl-3d0
+7fff0c000-7fff0d000 rw-s 00095000 00:10 20630 /dev/kgsl-3d0
+7fff0d000-7fff0e000 rw-s 00094000 00:10 20630 /dev/kgsl-3d0
+7fff0e000-7fff0f000 rw-s 00093000 00:10 20630 /dev/kgsl-3d0
+7fff0f000-7fff10000 rw-s 00092000 00:10 20630 /dev/kgsl-3d0
+7fff10000-7fff11000 rw-s 00091000 00:10 20630 /dev/kgsl-3d0
+7fff11000-7fff12000 rw-s 00090000 00:10 20630 /dev/kgsl-3d0
+7fff12000-7fff13000 rw-s 0008f000 00:10 20630 /dev/kgsl-3d0
+7fff13000-7fff14000 rw-s 0008e000 00:10 20630 /dev/kgsl-3d0
+7fff14000-7fff15000 rw-s 0008d000 00:10 20630 /dev/kgsl-3d0
+7fff15000-7fff16000 rw-s 0008c000 00:10 20630 /dev/kgsl-3d0
+7fff16000-7fff17000 rw-s 0008b000 00:10 20630 /dev/kgsl-3d0
+7fff17000-7fff18000 rw-s 0008a000 00:10 20630 /dev/kgsl-3d0
+7fff18000-7fff19000 rw-s 00089000 00:10 20630 /dev/kgsl-3d0
+7fff19000-7fff1a000 rw-s 00088000 00:10 20630 /dev/kgsl-3d0
+7fff1a000-7fff1b000 rw-s 00087000 00:10 20630 /dev/kgsl-3d0
+7fff1b000-7fff1c000 rw-s 00086000 00:10 20630 /dev/kgsl-3d0
+7fff1c000-7fff1d000 rw-s 00085000 00:10 20630 /dev/kgsl-3d0
+7fff1d000-7fff1e000 rw-s 00084000 00:10 20630 /dev/kgsl-3d0
+7fff1e000-7fff1f000 rw-s 00083000 00:10 20630 /dev/kgsl-3d0
+7fff1f000-7fff20000 rw-s 00082000 00:10 20630 /dev/kgsl-3d0
+7fff20000-7fff21000 rw-s 00081000 00:10 20630 /dev/kgsl-3d0
+7fff21000-7fff22000 rw-s 00080000 00:10 20630 /dev/kgsl-3d0
+7fff22000-7fff23000 rw-s 0007f000 00:10 20630 /dev/kgsl-3d0
+7fff23000-7fff24000 rw-s 0007e000 00:10 20630 /dev/kgsl-3d0
+7fff24000-7fff25000 rw-s 0007d000 00:10 20630 /dev/kgsl-3d0
+7fff25000-7fff26000 rw-s 0007c000 00:10 20630 /dev/kgsl-3d0
+7fff26000-7fff27000 rw-s 0007b000 00:10 20630 /dev/kgsl-3d0
+7fff27000-7fff28000 rw-s 0007a000 00:10 20630 /dev/kgsl-3d0
+7fff28000-7fff29000 rw-s 00079000 00:10 20630 /dev/kgsl-3d0
+7fff29000-7fff2a000 rw-s 00078000 00:10 20630 /dev/kgsl-3d0
+7fff2a000-7fff2b000 rw-s 00077000 00:10 20630 /dev/kgsl-3d0
+7fff2b000-7fff2c000 rw-s 00076000 00:10 20630 /dev/kgsl-3d0
+7fff2c000-7fff2d000 rw-s 00075000 00:10 20630 /dev/kgsl-3d0
+7fff2d000-7fff2e000 rw-s 00074000 00:10 20630 /dev/kgsl-3d0
+7fff2e000-7fff2f000 rw-s 00073000 00:10 20630 /dev/kgsl-3d0
+7fff2f000-7fff30000 rw-s 00072000 00:10 20630 /dev/kgsl-3d0
+7fff30000-7fff31000 rw-s 00071000 00:10 20630 /dev/kgsl-3d0
+7fff31000-7fff32000 rw-s 00070000 00:10 20630 /dev/kgsl-3d0
+7fff32000-7fff33000 rw-s 0006f000 00:10 20630 /dev/kgsl-3d0
+7fff33000-7fff34000 rw-s 0006e000 00:10 20630 /dev/kgsl-3d0
+7fff34000-7fff35000 rw-s 0006d000 00:10 20630 /dev/kgsl-3d0
+7fff35000-7fff36000 rw-s 0006c000 00:10 20630 /dev/kgsl-3d0
+7fff36000-7fff37000 rw-s 0006b000 00:10 20630 /dev/kgsl-3d0
+7fff37000-7fff38000 rw-s 0006a000 00:10 20630 /dev/kgsl-3d0
+7fff38000-7fff39000 rw-s 00069000 00:10 20630 /dev/kgsl-3d0
+7fff39000-7fff3a000 rw-s 00068000 00:10 20630 /dev/kgsl-3d0
+7fff3a000-7fff3b000 rw-s 00067000 00:10 20630 /dev/kgsl-3d0
+7fff3b000-7fff3c000 rw-s 00066000 00:10 20630 /dev/kgsl-3d0
+7fff3c000-7fff3d000 rw-s 00065000 00:10 20630 /dev/kgsl-3d0
+7fff3d000-7fff3e000 rw-s 00064000 00:10 20630 /dev/kgsl-3d0
+7fff3e000-7fff3f000 rw-s 00063000 00:10 20630 /dev/kgsl-3d0
+7fff3f000-7fff40000 rw-s 00062000 00:10 20630 /dev/kgsl-3d0
+7fff40000-7fff41000 rw-s 00061000 00:10 20630 /dev/kgsl-3d0
+7fff41000-7fff42000 rw-s 00060000 00:10 20630 /dev/kgsl-3d0
+7fff42000-7fff43000 rw-s 0005f000 00:10 20630 /dev/kgsl-3d0
+7fff43000-7fff44000 rw-s 0005e000 00:10 20630 /dev/kgsl-3d0
+7fff44000-7fff45000 rw-s 0005d000 00:10 20630 /dev/kgsl-3d0
+7fff45000-7fff46000 rw-s 0005c000 00:10 20630 /dev/kgsl-3d0
+7fff46000-7fff47000 rw-s 0005b000 00:10 20630 /dev/kgsl-3d0
+7fff47000-7fff48000 rw-s 0005a000 00:10 20630 /dev/kgsl-3d0
+7fff48000-7fff49000 rw-s 00059000 00:10 20630 /dev/kgsl-3d0
+7fff49000-7fff4a000 rw-s 00058000 00:10 20630 /dev/kgsl-3d0
+7fff4a000-7fff4b000 rw-s 00057000 00:10 20630 /dev/kgsl-3d0
+7fff4b000-7fff4c000 rw-s 00056000 00:10 20630 /dev/kgsl-3d0
+7fff4c000-7fff4d000 rw-s 00055000 00:10 20630 /dev/kgsl-3d0
+7fff4d000-7fff4e000 rw-s 00054000 00:10 20630 /dev/kgsl-3d0
+7fff4e000-7fff4f000 rw-s 00053000 00:10 20630 /dev/kgsl-3d0
+7fff4f000-7fff50000 rw-s 00052000 00:10 20630 /dev/kgsl-3d0
+7fff50000-7fff51000 rw-s 00051000 00:10 20630 /dev/kgsl-3d0
+7fff51000-7fff52000 rw-s 00050000 00:10 20630 /dev/kgsl-3d0
+7fff52000-7fff53000 rw-s 0004f000 00:10 20630 /dev/kgsl-3d0
+7fff53000-7fff54000 rw-s 0004e000 00:10 20630 /dev/kgsl-3d0
+7fff54000-7fff55000 rw-s 0004d000 00:10 20630 /dev/kgsl-3d0
+7fff55000-7fff56000 rw-s 0004c000 00:10 20630 /dev/kgsl-3d0
+7fff56000-7fff57000 rw-s 0004b000 00:10 20630 /dev/kgsl-3d0
+7fff57000-7fff58000 rw-s 0004a000 00:10 20630 /dev/kgsl-3d0
+7fff58000-7fff59000 rw-s 00049000 00:10 20630 /dev/kgsl-3d0
+7fff59000-7fff5a000 rw-s 00048000 00:10 20630 /dev/kgsl-3d0
+7fff5a000-7fff5b000 rw-s 00047000 00:10 20630 /dev/kgsl-3d0
+7fff5b000-7fff5c000 rw-s 00046000 00:10 20630 /dev/kgsl-3d0
+7fff5c000-7fff5d000 rw-s 00045000 00:10 20630 /dev/kgsl-3d0
+7fff5d000-7fff5e000 rw-s 00044000 00:10 20630 /dev/kgsl-3d0
+7fff5e000-7fff5f000 rw-s 00043000 00:10 20630 /dev/kgsl-3d0
+7fff5f000-7fff60000 rw-s 00042000 00:10 20630 /dev/kgsl-3d0
+7fff60000-7fff61000 rw-s 00041000 00:10 20630 /dev/kgsl-3d0
+7fff61000-7fff62000 rw-s 00040000 00:10 20630 /dev/kgsl-3d0
+7fff62000-7fff63000 rw-s 0003f000 00:10 20630 /dev/kgsl-3d0
+7fff63000-7fff64000 rw-s 0003e000 00:10 20630 /dev/kgsl-3d0
+7fff64000-7fff65000 rw-s 0003d000 00:10 20630 /dev/kgsl-3d0
+7fff65000-7fff66000 rw-s 0003c000 00:10 20630 /dev/kgsl-3d0
+7fff66000-7fff67000 rw-s 0003b000 00:10 20630 /dev/kgsl-3d0
+7fff67000-7fff68000 rw-s 0003a000 00:10 20630 /dev/kgsl-3d0
+7fff68000-7fff69000 rw-s 00039000 00:10 20630 /dev/kgsl-3d0
+7fff69000-7fff6a000 rw-s 00038000 00:10 20630 /dev/kgsl-3d0
+7fff6a000-7fff6b000 rw-s 00037000 00:10 20630 /dev/kgsl-3d0
+7fff6b000-7fff6c000 rw-s 00036000 00:10 20630 /dev/kgsl-3d0
+7fff6c000-7fff6d000 rw-s 00035000 00:10 20630 /dev/kgsl-3d0
+7fff6d000-7fff6e000 rw-s 00034000 00:10 20630 /dev/kgsl-3d0
+7fff6e000-7fff6f000 rw-s 00033000 00:10 20630 /dev/kgsl-3d0
+7fff6f000-7fff70000 rw-s 00032000 00:10 20630 /dev/kgsl-3d0
+7fff70000-7fff71000 rw-s 00031000 00:10 20630 /dev/kgsl-3d0
+7fff71000-7fff72000 rw-s 00030000 00:10 20630 /dev/kgsl-3d0
+7fff72000-7fff73000 rw-s 0002f000 00:10 20630 /dev/kgsl-3d0
+7fff73000-7fff74000 rw-s 0002e000 00:10 20630 /dev/kgsl-3d0
+7fff74000-7fff75000 rw-s 0002d000 00:10 20630 /dev/kgsl-3d0
+7fff75000-7fff76000 rw-s 0002c000 00:10 20630 /dev/kgsl-3d0
+7fff76000-7fff77000 rw-s 0002b000 00:10 20630 /dev/kgsl-3d0
+7fff77000-7fff78000 rw-s 0002a000 00:10 20630 /dev/kgsl-3d0
+7fff78000-7fff79000 rw-s 00029000 00:10 20630 /dev/kgsl-3d0
+7fff79000-7fff7a000 rw-s 00028000 00:10 20630 /dev/kgsl-3d0
+7fff7a000-7fff7b000 rw-s 00027000 00:10 20630 /dev/kgsl-3d0
+7fff7b000-7fff7c000 rw-s 00026000 00:10 20630 /dev/kgsl-3d0
+7fff7c000-7fff7d000 rw-s 00025000 00:10 20630 /dev/kgsl-3d0
+7fff7d000-7fff7e000 rw-s 00024000 00:10 20630 /dev/kgsl-3d0
+7fff7e000-7fff7f000 rw-s 00023000 00:10 20630 /dev/kgsl-3d0
+7fff7f000-7fff80000 rw-s 00022000 00:10 20630 /dev/kgsl-3d0
+7fff80000-7fff90000 rw-s 00019000 00:10 20630 /dev/kgsl-3d0
+7fff90000-7fffb0000 rw-s 00018000 00:10 20630 /dev/kgsl-3d0
+7fffb1000-7fffb2000 rw-s 00021000 00:10 20630 /dev/kgsl-3d0
+7fffb2000-7fffb3000 rw-s 00020000 00:10 20630 /dev/kgsl-3d0
+7fffb3000-7fffb4000 rw-s 0001f000 00:10 20630 /dev/kgsl-3d0
+7fffba000-7fffbe000 rw-s 0001b000 00:10 20630 /dev/kgsl-3d0
+7fffbe000-7fffbf000 rw-s 0001a000 00:10 20630 /dev/kgsl-3d0
+7fffbf000-7fffc0000 rw-s 00017000 00:10 20630 /dev/kgsl-3d0
+7fffc0000-7fffe0000 rw-s 00016000 00:10 20630 /dev/kgsl-3d0
+7fffe0000-7fffe1000 rw-s 00014000 00:10 20630 /dev/kgsl-3d0
+7fffe1000-7fffe5000 rw-s 00013000 00:10 20630 /dev/kgsl-3d0
+7fffe5000-7fffe6000 rw-s 00012000 00:10 20630 /dev/kgsl-3d0
+7fffe6000-7fffe7000 rw-s 00011000 00:10 20630 /dev/kgsl-3d0
+7fffe7000-7fffe8000 rw-s 00010000 00:10 20630 /dev/kgsl-3d0
+7fffe8000-7fffe9000 rw-s 0000f000 00:10 20630 /dev/kgsl-3d0
+7fffe9000-7fffea000 rw-s 0000e000 00:10 20630 /dev/kgsl-3d0
+7fffea000-7fffeb000 rw-s 0000d000 00:10 20630 /dev/kgsl-3d0
+7fffeb000-7fffec000 rw-s 0000c000 00:10 20630 /dev/kgsl-3d0
+7fffec000-7ffff0000 rw-s 0000b000 00:10 20630 /dev/kgsl-3d0
+7ffff0000-7ffff1000 rw-s 0000a000 00:10 20630 /dev/kgsl-3d0
+7ffff1000-7ffff5000 rw-s 00009000 00:10 20630 /dev/kgsl-3d0
+7ffff5000-7ffff6000 rw-s 00008000 00:10 20630 /dev/kgsl-3d0
+7ffff6000-7ffff7000 rw-s 00007000 00:10 20630 /dev/kgsl-3d0
+7ffff7000-7ffff8000 rw-s 00006000 00:10 20630 /dev/kgsl-3d0
+7ffff8000-7ffff9000 rw-s 00005000 00:10 20630 /dev/kgsl-3d0
+7ffff9000-7ffffa000 rw-s 00004000 00:10 20630 /dev/kgsl-3d0
+7ffffa000-7ffffb000 rw-s 00003000 00:10 20630 /dev/kgsl-3d0
+7ffffb000-7ffffc000 rw-s 00002000 00:10 20630 /dev/kgsl-3d0
+7ffffc000-800000000 rw-s 00001000 00:10 20630 /dev/kgsl-3d0
+5ff1d4f000-5ff1d54000 r-xp 00000000 fc:00 3419 /system/bin/app_process64
+5ff1d6e000-5ff1d6f000 r--p 0000f000 fc:00 3419 /system/bin/app_process64
+5ff1d6f000-5ff1d71000 rw-p 00000000 00:00 0
+704defa000-704defb000 ---p 00000000 00:00 0 [anon:thread stack guard]
+704defb000-704defc000 ---p 00000000 00:00 0
+704defc000-704e000000 rw-p 00000000 00:00 0
+704e000000-704e400000 rw-p 00000000 00:00 0 [anon:libc_malloc]
+704e455000-704e456000 ---p 00000000 00:00 0 [anon:thread stack guard]
+704e456000-704e457000 ---p 00000000 00:00 0
+704e457000-704e553000 rw-p 00000000 00:00 0
+704e553000-704e651000 r--p 00000000 00:10 16029 /dev/hwbinder
+704e651000-704e65f000 r-xp 00000000 fc:01 1040 /vendor/lib64/egl/eglSubDriverAndroid.so
+704e65f000-704e660000 r--p 0000e000 fc:01 1040 /vendor/lib64/egl/eglSubDriverAndroid.so
+704e660000-704e661000 rw-p 0000f000 fc:01 1040 /vendor/lib64/egl/eglSubDriverAndroid.so
+704e69d000-704e69e000 ---p 00000000 00:00 0 [anon:thread stack guard]
+704e69e000-704e79b000 rw-p 00000000 00:00 0
+704e79b000-704f79b000 rw-s 00000000 00:05 10271021 /dev/ashmem/AudioFlinger::Client(29312) (deleted)
+704f79b000-704f79c000 ---p 00000000 00:00 0 [anon:thread stack guard]
+704f79c000-704f899000 rw-p 00000000 00:00 0
+704f899000-704f89a000 ---p 00000000 00:00 0 [anon:thread stack guard]
+704f89a000-704f89b000 ---p 00000000 00:00 0
+704f89b000-704f997000 rw-p 00000000 00:00 0
+704f997000-704f9ee000 r-xp 00000000 103:1d 1737338 /data/app/com.google.sample.tunnel-HGGRU03Gu1Mwkf_-RnFmvw==/lib/arm64/libgame.so
+704f9ee000-704f9fd000 ---p 00000000 00:00 0
+704f9fd000-704fa00000 r--p 00056000 103:1d 1737338 /data/app/com.google.sample.tunnel-HGGRU03Gu1Mwkf_-RnFmvw==/lib/arm64/libgame.so
+704fa00000-704fa01000 rw-p 00059000 103:1d 1737338 /data/app/com.google.sample.tunnel-HGGRU03Gu1Mwkf_-RnFmvw==/lib/arm64/libgame.so
+704fa01000-704fa19000 rw-p 00000000 00:00 0 [anon:.bss]
+704fa40000-70507e7000 r-xp 00000000 fc:01 1026 /vendor/lib64/libllvm-glnext.so
+70507e7000-70507fc000 ---p 00000000 00:00 0
+70507fc000-7050835000 r--p 00da7000 fc:01 1026 /vendor/lib64/libllvm-glnext.so
+7050835000-705083a000 rw-p 00de0000 fc:01 1026 /vendor/lib64/libllvm-glnext.so
+705083a000-7050855000 rw-p 00000000 00:00 0 [anon:.bss]
+705089b000-7050f19000 r-xp 00000000 fc:01 1039 /vendor/lib64/egl/libGLESv2_adreno.so
+7050f19000-7050f22000 r--p 0067e000 fc:01 1039 /vendor/lib64/egl/libGLESv2_adreno.so
+7050f22000-7050f29000 rw-p 00687000 fc:01 1039 /vendor/lib64/egl/libGLESv2_adreno.so
+7050f29000-7050f2c000 rw-p 00000000 00:00 0 [anon:.bss]
+7050f83000-7050fbc000 r-xp 00000000 fc:01 1041 /vendor/lib64/egl/libGLESv1_CM_adreno.so
+7050fbc000-7050fbd000 r--p 00039000 fc:01 1041 /vendor/lib64/egl/libGLESv1_CM_adreno.so
+7050fbd000-7050fbe000 rw-p 0003a000 fc:01 1041 /vendor/lib64/egl/libGLESv1_CM_adreno.so
+7050fbe000-7050fbf000 rw-p 00000000 00:00 0 [anon:.bss]
+7050fc6000-705111d000 r-xp 00000000 fc:01 865 /vendor/lib64/libgsl.so
+705111d000-705111e000 r--p 00157000 fc:01 865 /vendor/lib64/libgsl.so
+705111e000-705111f000 rw-p 00158000 fc:01 865 /vendor/lib64/libgsl.so
+705111f000-7051120000 rw-p 00000000 00:00 0 [anon:.bss]
+7051146000-705115d000 r-xp 00000000 fc:00 2587 /system/lib64/vndk-sp-28/libz.so
+705115d000-7051175000 ---p 00000000 00:00 0
+7051175000-7051176000 r--p 0001f000 fc:00 2587 /system/lib64/vndk-sp-28/libz.so
+7051176000-7051177000 rw-p 00020000 fc:00 2587 /system/lib64/vndk-sp-28/libz.so
+705119f000-70511ac000 r-xp 00000000 fc:01 886 /vendor/lib64/libadreno_utils.so
+70511ac000-70511ad000 r--p 0000d000 fc:01 886 /vendor/lib64/libadreno_utils.so
+70511ad000-70511ae000 rw-p 0000e000 fc:01 886 /vendor/lib64/libadreno_utils.so
+70511ae000-70511b0000 rw-p 00000000 00:00 0 [anon:.bss]
+70511c0000-70511d7000 r-xp 00000000 fc:01 1044 /vendor/lib64/egl/libEGL_adreno.so
+70511d7000-70511d8000 r--p 00017000 fc:01 1044 /vendor/lib64/egl/libEGL_adreno.so
+70511d8000-70511d9000 rw-p 00018000 fc:01 1044 /vendor/lib64/egl/libEGL_adreno.so
+70511d9000-70511da000 rw-p 00000000 00:00 0 [anon:.bss]
+705120a000-705120d000 r-xp 00000000 fc:01 972 /vendor/lib64/libdrmutils.so
+705120d000-7051229000 ---p 00000000 00:00 0
+7051229000-705122a000 r--p 0000f000 fc:01 972 /vendor/lib64/libdrmutils.so
+705122a000-705122b000 rw-p 00010000 fc:01 972 /vendor/lib64/libdrmutils.so
+705125a000-705125c000 r-xp 00000000 fc:01 1046 /vendor/lib64/libqdMetaData.so
+705125c000-7051279000 ---p 00000000 00:00 0
+7051279000-705127a000 r--p 0000f000 fc:01 1046 /vendor/lib64/libqdMetaData.so
+705127a000-705127b000 rw-p 00010000 fc:01 1046 /vendor/lib64/libqdMetaData.so
+7051286000-7051297000 r-xp 00000000 fc:01 1024 /vendor/lib64/libdrm.so
+7051297000-70512b5000 ---p 00000000 00:00 0
+70512b5000-70512b6000 r--p 0001f000 fc:01 1024 /vendor/lib64/libdrm.so
+70512b6000-70512b7000 rw-p 00020000 fc:01 1024 /vendor/lib64/libdrm.so
+70512cb000-70512de000 r-xp 00000000 fc:01 1008 /vendor/lib64/hw/gralloc.msm8998.so
+70512de000-70512fa000 ---p 00000000 00:00 0
+70512fa000-70512fb000 r--p 0001f000 fc:01 1008 /vendor/lib64/hw/gralloc.msm8998.so
+70512fb000-70512fc000 rw-p 00020000 fc:01 1008 /vendor/lib64/hw/gralloc.msm8998.so
+7051326000-7051327000 ---p 00000000 00:00 0 [anon:thread stack guard]
+7051327000-7051328000 ---p 00000000 00:00 0
+7051328000-7051424000 rw-p 00000000 00:00 0
+7051424000-705143d000 r--p 00000000 fc:00 739 /system/framework/oat/arm64/org.apache.http.legacy.boot.odex
+705143d000-7051480000 r-xp 00019000 fc:00 739 /system/framework/oat/arm64/org.apache.http.legacy.boot.odex
+7051480000-7051494000 r--p 00211000 103:1d 639511 /data/dalvik-cache/arm64/system@framework@boot.art
+7051494000-705149f000 r--p 000c5000 103:1d 639514 /data/dalvik-cache/arm64/system@framework@boot-core-libart.art
+705149f000-70514a2000 r--p 00032000 103:1d 639517 /data/dalvik-cache/arm64/system@framework@boot-conscrypt.art
+70514a2000-70514a5000 r--p 0002b000 103:1d 639520 /data/dalvik-cache/arm64/system@framework@boot-okhttp.art
+70514a5000-70514ac000 r--p 0003f000 103:1d 639523 /data/dalvik-cache/arm64/system@framework@boot-bouncycastle.art
+70514ac000-70514b2000 r--p 00044000 103:1d 639526 /data/dalvik-cache/arm64/system@framework@boot-apache-xml.art
+70514b2000-70514bd000 r--p 00035000 103:1d 639529 /data/dalvik-cache/arm64/system@framework@boot-ext.art
+70514bd000-70514f4000 r--p 0060f000 103:1d 639532 /data/dalvik-cache/arm64/system@framework@boot-framework.art
+70514f4000-70514fe000 r--p 00054000 103:1d 639535 /data/dalvik-cache/arm64/system@framework@boot-telephony-common.art
+70514fe000-70514ff000 r--p 0000c000 103:1d 639538 /data/dalvik-cache/arm64/system@framework@boot-voip-common.art
+70514ff000-7051500000 r--p 0000e000 103:1d 639541 /data/dalvik-cache/arm64/system@framework@boot-ims-common.art
+7051500000-7051501000 r--p 00004000 103:1d 639547 /data/dalvik-cache/arm64/system@framework@boot-android.hidl.manager-V1.0-java.art
+7051501000-7051502000 r--p 00004000 103:1d 639553 /data/dalvik-cache/arm64/system@framework@boot-android.test.base.art
+7051502000-7051503000 r--p 00001000 103:1d 639556 /data/dalvik-cache/arm64/system@framework@boot-com.google.vr.platform.art
+7051503000-7051504000 rw-p 00000000 00:00 0 [anon:.bss]
+7051504000-7051579000 r--s 00000000 fc:00 790 /system/framework/oat/arm64/org.apache.http.legacy.boot.vdex
+7051579000-705157a000 r--p 0005c000 fc:00 739 /system/framework/oat/arm64/org.apache.http.legacy.boot.odex
+705157a000-705157b000 rw-p 0005d000 fc:00 739 /system/framework/oat/arm64/org.apache.http.legacy.boot.odex
+705158b000-7057f4d000 ---p 00000000 00:00 0
+7057f4d000-7057f4f000 r-xp 00000000 fc:00 2646 /system/lib64/libwebviewchromium_loader.so
+7057f4f000-7057f6c000 ---p 00000000 00:00 0
+7057f6c000-7057f6d000 r--p 0000f000 fc:00 2646 /system/lib64/libwebviewchromium_loader.so
+7057f6d000-7057f6e000 rw-p 00010000 fc:00 2646 /system/lib64/libwebviewchromium_loader.so
+7057f76000-7057f96000 r--s 00000000 00:10 16615 /dev/__properties__/u:object_r:hwservicemanager_prop:s0
+7057f96000-7057fb6000 r--s 00000000 00:10 16639 /dev/__properties__/u:object_r:public_vendor_default_prop:s0
+7057fb6000-7058004000 r--s 00000000 fc:00 1112 /system/usr/hyphen-data/hyph-hu.hyb
+7058004000-7058024000 r-xp 00000000 fc:00 2354 /system/lib64/libcompiler_rt.so
+7058024000-7058043000 ---p 00000000 00:00 0
+7058043000-7058044000 r--p 0002f000 fc:00 2354 /system/lib64/libcompiler_rt.so
+7058044000-7058045000 rw-p 00030000 fc:00 2354 /system/lib64/libcompiler_rt.so
+7058045000-70580b2000 rw-p 00000000 00:00 0 [anon:.bss]
+70580bd000-70580dd000 rw-p 00000000 00:05 10265386 /dev/ashmem/dalvik-LinearAlloc (deleted)
+70580dd000-70580df000 r-xp 00000000 fc:00 2597 /system/lib64/vndk-sp-28/libhardware.so
+70580df000-70580fc000 ---p 00000000 00:00 0
+70580fc000-70580fd000 r--p 0000f000 fc:00 2597 /system/lib64/vndk-sp-28/libhardware.so
+70580fd000-70580fe000 rw-p 00010000 fc:00 2597 /system/lib64/vndk-sp-28/libhardware.so
+705810e000-705811f000 r-xp 00000000 fc:00 2589 /system/lib64/vndk-sp-28/libbase.so
+705811f000-705813d000 ---p 00000000 00:00 0
+705813d000-705813e000 r--p 0001f000 fc:00 2589 /system/lib64/vndk-sp-28/libbase.so
+705813e000-705813f000 rw-p 00020000 fc:00 2589 /system/lib64/vndk-sp-28/libbase.so
+7058140000-7058167000 r-xp 00000000 fc:00 2572 /system/lib64/vndk-sp-28/libhwbinder.so
+7058167000-705817d000 ---p 00000000 00:00 0
+705817d000-705817f000 r--p 0002e000 fc:00 2572 /system/lib64/vndk-sp-28/libhwbinder.so
+705817f000-7058180000 rw-p 00030000 fc:00 2572 /system/lib64/vndk-sp-28/libhwbinder.so
+705818c000-705818d000 r-xp 00000000 fc:00 2584 /system/lib64/vndk-sp-28/android.hardware.graphics.common@1.0.so
+705818d000-70581ab000 ---p 00000000 00:00 0
+70581ab000-70581ac000 r--p 0000f000 fc:00 2584 /system/lib64/vndk-sp-28/android.hardware.graphics.common@1.0.so
+70581ac000-70581ad000 rw-p 00010000 fc:00 2584 /system/lib64/vndk-sp-28/android.hardware.graphics.common@1.0.so
+70581b7000-70581d7000 r--s 00000000 00:10 16619 /dev/__properties__/u:object_r:log_prop:s0
+70581d7000-7058237000 r-xp 00000000 fc:00 2574 /system/lib64/vndk-sp-28/libhidltransport.so
+7058237000-7058255000 ---p 00000000 00:00 0
+7058255000-705825d000 r--p 00068000 fc:00 2574 /system/lib64/vndk-sp-28/libhidltransport.so
+705825d000-705825e000 rw-p 00070000 fc:00 2574 /system/lib64/vndk-sp-28/libhidltransport.so
+7058260000-7058284000 r--s 00000000 fc:00 1138 /system/usr/hyphen-data/hyph-nn.hyb
+7058284000-70582a0000 r-xp 00000000 fc:00 2576 /system/lib64/vndk-sp-28/libutils.so
+70582a0000-70582b3000 ---p 00000000 00:00 0
+70582b3000-70582b4000 r--p 0001f000 fc:00 2576 /system/lib64/vndk-sp-28/libutils.so
+70582b4000-70582b5000 rw-p 00020000 fc:00 2576 /system/lib64/vndk-sp-28/libutils.so
+70582c4000-7058391000 r-xp 00000000 fc:00 2568 /system/lib64/vndk-sp-28/libc++.so
+7058391000-70583ad000 ---p 00000000 00:00 0
+70583ad000-70583b7000 r--p 000d6000 fc:00 2568 /system/lib64/vndk-sp-28/libc++.so
+70583b7000-70583b8000 rw-p 000e0000 fc:00 2568 /system/lib64/vndk-sp-28/libc++.so
+70583b8000-70583bb000 rw-p 00000000 00:00 0 [anon:.bss]
+70583cd000-70583e4000 r-xp 00000000 fc:00 2580 /system/lib64/vndk-sp-28/android.hardware.graphics.mapper@2.0.so
+70583e4000-70583f9000 ---p 00000000 00:00 0
+70583f9000-70583fb000 r--p 0001e000 fc:00 2580 /system/lib64/vndk-sp-28/android.hardware.graphics.mapper@2.0.so
+70583fb000-70583fc000 rw-p 00020000 fc:00 2580 /system/lib64/vndk-sp-28/android.hardware.graphics.mapper@2.0.so
+705841b000-7058421000 r-xp 00000000 fc:01 1001 /vendor/lib64/hw/android.hardware.graphics.mapper@2.0-impl.so
+7058421000-705843a000 ---p 00000000 00:00 0
+705843a000-705843b000 r--p 0000f000 fc:01 1001 /vendor/lib64/hw/android.hardware.graphics.mapper@2.0-impl.so
+705843b000-705843c000 rw-p 00010000 fc:01 1001 /vendor/lib64/hw/android.hardware.graphics.mapper@2.0-impl.so
+705844f000-7058473000 r--s 00000000 fc:00 1150 /system/usr/hyphen-data/hyph-nb.hyb
+7058473000-7058495000 r-xp 00000000 fc:00 2582 /system/lib64/vndk-sp-28/libhidlbase.so
+7058495000-70584b1000 ---p 00000000 00:00 0
+70584b1000-70584b3000 r--p 0002e000 fc:00 2582 /system/lib64/vndk-sp-28/libhidlbase.so
+70584b3000-70584b4000 rw-p 00030000 fc:00 2582 /system/lib64/vndk-sp-28/libhidlbase.so
+70584cd000-70584df000 r-xp 00000000 fc:00 2595 /system/lib64/vndk-sp-28/libcutils.so
+70584df000-70584fb000 ---p 00000000 00:00 0
+70584fb000-70584fd000 r--p 0001e000 fc:00 2595 /system/lib64/vndk-sp-28/libcutils.so
+70584fd000-70584fe000 rw-p 00020000 fc:00 2595 /system/lib64/vndk-sp-28/libcutils.so
+7058519000-7058537000 r--s 00000000 fc:00 1124 /system/usr/hyphen-data/hyph-de-ch-1901.hyb
+7058537000-7059fd1000 r--s 0070b000 fc:00 989 /system/framework/framework-res.apk
+7059fd1000-705a013000 r-xp 00000000 fc:00 2610 /system/lib64/libjavacrypto.so
+705a013000-705a02b000 ---p 00000000 00:00 0
+705a02b000-705a02d000 r--p 0004e000 fc:00 2610 /system/lib64/libjavacrypto.so
+705a02d000-705a02f000 rw-p 00050000 fc:00 2610 /system/lib64/libjavacrypto.so
+705a041000-705a05f000 r--s 00000000 fc:00 1128 /system/usr/hyphen-data/hyph-de-1996.hyb
+705a05f000-705a06a000 r-xp 00000000 fc:00 2917 /system/lib64/libsoundpool.so
+705a06a000-705a07e000 ---p 00000000 00:00 0
+705a07e000-705a07f000 r--p 0000f000 fc:00 2917 /system/lib64/libsoundpool.so
+705a07f000-705a080000 rw-p 00010000 fc:00 2917 /system/lib64/libsoundpool.so
+705a087000-705a102000 r--s 00000000 fc:00 1246 /system/usr/share/zoneinfo/tzdata
+705a102000-705a863000 r--s 00000000 fc:00 101 /system/fonts/NotoColorEmoji.ttf
+705a863000-705c000000 r--s 00000000 fc:00 251 /system/fonts/NotoSerifCJK-Regular.ttc
+705c000000-705c200000 rw-p 00000000 00:00 0 [anon:libc_malloc]
+705c209000-705c227000 r--s 00000000 fc:00 1077 /system/usr/hyphen-data/hyph-de-1901.hyb
+705c227000-705c26e000 r--s 02284000 fc:00 989 /system/framework/framework-res.apk
+705c26e000-705d43e000 r--s 00000000 fc:00 95 /system/fonts/NotoSansCJK-Regular.ttc
+705d43e000-705d4ec000 r--s 00000000 fc:00 278 /system/fonts/NotoSansSymbols-Regular-Subsetted.ttf
+705d4ec000-705d548000 r--s 00000000 fc:00 233 /system/fonts/NotoSansTibetan-Bold.ttf
+705d548000-705d5ab000 r--s 00000000 fc:00 177 /system/fonts/NotoSansTibetan-Regular.ttf
+705d5ab000-705d627000 r--s 00000000 fc:00 197 /system/fonts/NotoSansEgyptianHieroglyphs-Regular.ttf
+705d627000-705d6a2000 r--s 00000000 fc:00 76 /system/fonts/NotoSansCuneiform-Regular.ttf
+705d6a2000-705d6f3000 r--s 00000000 fc:00 67 /system/fonts/RobotoCondensed-BoldItalic.ttf
+705d6f3000-705d73e000 r--s 00000000 fc:00 199 /system/fonts/RobotoCondensed-Bold.ttf
+705d73e000-705d78f000 r--s 00000000 fc:00 230 /system/fonts/RobotoCondensed-MediumItalic.ttf
+705d78f000-705d7da000 r--s 00000000 fc:00 92 /system/fonts/RobotoCondensed-Medium.ttf
+705d7da000-705d82b000 r--s 00000000 fc:00 128 /system/fonts/RobotoCondensed-Italic.ttf
+705d82b000-705d875000 r--s 00000000 fc:00 164 /system/fonts/RobotoCondensed-Regular.ttf
+705d875000-705d8c7000 r--s 00000000 fc:00 292 /system/fonts/RobotoCondensed-LightItalic.ttf
+705d8c7000-705d919000 r--s 00000000 fc:00 85 /system/fonts/Roboto-BoldItalic.ttf
+705d919000-705d964000 r--s 00000000 fc:00 175 /system/fonts/Roboto-Bold.ttf
+705d964000-705d9b5000 r--s 00000000 fc:00 266 /system/fonts/Roboto-BlackItalic.ttf
+705d9b5000-705da00000 r--s 00000000 fc:00 187 /system/fonts/Roboto-Black.ttf
+705da00000-705dc00000 rw-p 00000000 00:00 0 [anon:libc_malloc]
+705dc1d000-705dc6e000 r--s 00000000 fc:00 148 /system/fonts/Roboto-MediumItalic.ttf
+705dc6e000-705dcb9000 r--s 00000000 fc:00 284 /system/fonts/Roboto-Medium.ttf
+705dcb9000-705dd0a000 r--s 00000000 fc:00 105 /system/fonts/Roboto-Italic.ttf
+705dd0a000-705dd55000 r--s 00000000 fc:00 156 /system/fonts/Roboto-Regular.ttf
+705dd55000-705dda7000 r--s 00000000 fc:00 217 /system/fonts/Roboto-LightItalic.ttf
+705dda7000-705ddf8000 r--s 00000000 fc:00 166 /system/fonts/Roboto-ThinItalic.ttf
+705ddf8000-705ddf9000 ---p 00000000 00:00 0 [anon:thread stack guard]
+705ddf9000-705ddfa000 ---p 00000000 00:00 0
+705ddfa000-705def6000 rw-p 00000000 00:00 0
+705def6000-705f5ec000 r--s 00000000 fc:00 1350 /system/usr/icu/icudt60l.dat
+705f5ec000-705f5ed000 ---p 00000000 00:00 0 [anon:thread stack guard]
+705f5ed000-705f5ee000 ---p 00000000 00:00 0
+705f5ee000-705f6ea000 rw-p 00000000 00:00 0
+705f6ea000-705f7e8000 r--p 00000000 00:10 20636 /dev/binder
+705f7e8000-705f7e9000 ---p 00000000 00:00 0 [anon:thread stack guard]
+705f7e9000-705f7ea000 ---p 00000000 00:00 0
+705f7ea000-705f8ee000 rw-p 00000000 00:00 0
+705f8ee000-705f8ef000 ---p 00000000 00:00 0 [anon:thread stack guard]
+705f8ef000-705f8f0000 ---p 00000000 00:00 0
+705f8f0000-705f9f4000 rw-p 00000000 00:00 0
+705f9f4000-705f9f5000 ---p 00000000 00:00 0 [anon:thread stack guard]
+705f9f5000-705f9f6000 ---p 00000000 00:00 0
+705f9f6000-705fafa000 rw-p 00000000 00:00 0
+705fafa000-705fafb000 ---p 00000000 00:00 0 [anon:thread stack guard]
+705fafb000-705fafc000 ---p 00000000 00:00 0
+705fafc000-705fc00000 rw-p 00000000 00:00 0
+705fc00000-705fe00000 rw-p 00000000 00:00 0 [anon:libc_malloc]
+705fe01000-705fe4c000 r--s 00000000 fc:00 97 /system/fonts/Roboto-Light.ttf
+705fe4c000-705fe4d000 ---p 00000000 00:00 0 [anon:thread stack guard]
+705fe4d000-705fe4e000 ---p 00000000 00:00 0
+705fe4e000-705ff4a000 rw-p 00000000 00:00 0
+705ff4a000-705ff4b000 ---p 00000000 00:05 10270991 /dev/ashmem/dalvik-Jit thread pool worker thread 0 (deleted)
+705ff4b000-705ff4c000 ---p 00001000 00:05 10270991 /dev/ashmem/dalvik-Jit thread pool worker thread 0 (deleted)
+705ff4c000-706004b000 rw-p 00002000 00:05 10270991 /dev/ashmem/dalvik-Jit thread pool worker thread 0 (deleted)
+706004b000-706010f000 r-xp 00000000 fc:00 2390 /system/lib64/libvixl-arm64.so
+706010f000-7060120000 ---p 00000000 00:00 0
+7060120000-7060125000 r--p 000cb000 fc:00 2390 /system/lib64/libvixl-arm64.so
+7060125000-7060126000 rw-p 000d0000 fc:00 2390 /system/lib64/libvixl-arm64.so
+7060126000-706012d000 rw-p 00000000 00:00 0 [anon:.bss]
+7060135000-7060151000 r--s 00000000 fc:01 1180 /vendor/overlay/framework-res__auto_generated_rro.apk
+7060151000-7060263000 r-xp 00000000 fc:00 2669 /system/lib64/libvixl-arm.so
+7060263000-7060275000 ---p 00000000 00:00 0
+7060275000-706027a000 r--p 0011b000 fc:00 2669 /system/lib64/libvixl-arm.so
+706027a000-706027b000 rw-p 00120000 fc:00 2669 /system/lib64/libvixl-arm.so
+706028b000-706056c000 r-xp 00000000 fc:00 2972 /system/lib64/libart-compiler.so
+706056c000-7060580000 ---p 00000000 00:00 0
+7060580000-7060598000 r--p 002e8000 fc:00 2972 /system/lib64/libart-compiler.so
+7060598000-7060599000 rw-p 00300000 fc:00 2972 /system/lib64/libart-compiler.so
+7060599000-70605a0000 rw-p 00000000 00:00 0 [anon:.bss]
+70605b0000-70605d0000 r--s 00000000 00:10 16571 /dev/__properties__/u:object_r:config_prop:s0
+70605d0000-7060619000 r-xp 00000000 fc:00 2702 /system/lib64/libssl.so
+7060619000-706062d000 ---p 00000000 00:00 0
+706062d000-7060630000 r--p 0004d000 fc:00 2702 /system/lib64/libssl.so
+7060630000-7060631000 rw-p 00050000 fc:00 2702 /system/lib64/libssl.so
+7060647000-7060667000 r--s 00000000 00:10 16595 /dev/__properties__/u:object_r:exported3_radio_prop:s0
+7060667000-706069d000 r-xp 00000000 fc:00 2371 /system/lib64/libopenjdk.so
+706069d000-70606b2000 ---p 00000000 00:00 0
+70606b2000-70606b4000 r--p 0003e000 fc:00 2371 /system/lib64/libopenjdk.so
+70606b4000-70606b6000 rw-p 00040000 fc:00 2371 /system/lib64/libopenjdk.so
+70606bb000-70606db000 r--s 00000000 00:10 16608 /dev/__properties__/u:object_r:exported_system_prop:s0
+70606db000-70606e3000 r-xp 00000000 fc:00 2538 /system/lib64/libopenjdkjvm.so
+70606e3000-70606fa000 ---p 00000000 00:00 0
+70606fa000-70606fb000 r--p 0000f000 fc:00 2538 /system/lib64/libopenjdkjvm.so
+70606fb000-70606fc000 rw-p 00010000 fc:00 2538 /system/lib64/libopenjdkjvm.so
+7060701000-7060722000 r--s 00000000 fc:00 227 /system/fonts/NotoSansAnatolianHieroglyphs-Regular.otf
+7060722000-7061e18000 r--s 00000000 fc:00 1350 /system/usr/icu/icudt60l.dat
+7061e18000-7061e5d000 r-xp 00000000 fc:00 2368 /system/lib64/libjavacore.so
+7061e5d000-7061e71000 ---p 00000000 00:00 0
+7061e71000-7061e73000 r--p 0004e000 fc:00 2368 /system/lib64/libjavacore.so
+7061e73000-7061e75000 rw-p 00050000 fc:00 2368 /system/lib64/libjavacore.so
+7061e75000-7061e76000 rw-p 00000000 00:00 0 [anon:.bss]
+7061e77000-7061e96000 r--s 00000000 fc:00 186 /system/fonts/NotoSansYi-Regular.ttf
+7061e96000-7061e99000 r-xp 00000000 fc:00 2953 /system/lib64/libwebviewchromium_plat_support.so
+7061e99000-7061eb5000 ---p 00000000 00:00 0
+7061eb5000-7061eb6000 r--p 0000f000 fc:00 2953 /system/lib64/libwebviewchromium_plat_support.so
+7061eb6000-7061eb7000 rw-p 00010000 fc:00 2953 /system/lib64/libwebviewchromium_plat_support.so
+7061ebc000-7061edd000 r--s 00000000 fc:00 100 /system/fonts/NotoSansBamum-Regular.ttf
+7061edd000-7061eed000 r-xp 00000000 fc:00 2945 /system/lib64/libRS.so
+7061eed000-7061efc000 ---p 00000000 00:00 0
+7061efc000-7061efd000 r--p 0000f000 fc:00 2945 /system/lib64/libRS.so
+7061efd000-7061efe000 rw-p 00010000 fc:00 2945 /system/lib64/libRS.so
+7061f05000-7061f6b000 r-xp 00000000 fc:00 2423 /system/lib64/android.hardware.renderscript@1.0.so
+7061f6b000-7061f7a000 ---p 00000000 00:00 0
+7061f7a000-7061f7f000 r--p 0006b000 fc:00 2423 /system/lib64/android.hardware.renderscript@1.0.so
+7061f7f000-7061f80000 rw-p 00070000 fc:00 2423 /system/lib64/android.hardware.renderscript@1.0.so
+7061f99000-7061f9b000 r-xp 00000000 fc:00 2614 /system/lib64/libOpenSLES.so
+7061f9b000-7061fb8000 ---p 00000000 00:00 0
+7061fb8000-7061fb9000 r--p 0000f000 fc:00 2614 /system/lib64/libOpenSLES.so
+7061fb9000-7061fba000 rw-p 00010000 fc:00 2614 /system/lib64/libOpenSLES.so
+7061fc6000-7061fc8000 r-xp 00000000 fc:00 2963 /system/lib64/libOpenMAXAL.so
+7061fc8000-7061fe5000 ---p 00000000 00:00 0
+7061fe5000-7061fe6000 r--p 0000f000 fc:00 2963 /system/lib64/libOpenMAXAL.so
+7061fe6000-7061fe7000 rw-p 00010000 fc:00 2963 /system/lib64/libOpenMAXAL.so
+7061fe7000-7062000000 r--s 00000000 fc:00 143 /system/fonts/NotoSansBhaiksuki-Regular.otf
+7062000000-7062003000 r-xp 00000000 fc:00 2447 /system/lib64/libtextclassifier_hash.so
+7062003000-706201f000 ---p 00000000 00:00 0
+706201f000-7062020000 r--p 0000f000 fc:00 2447 /system/lib64/libtextclassifier_hash.so
+7062020000-7062021000 rw-p 00010000 fc:00 2447 /system/lib64/libtextclassifier_hash.so
+7062022000-7062042000 rw-p 00000000 00:05 10269731 /dev/ashmem/dalvik-CompilerMetadata (deleted)
+7062042000-7062077000 r-xp 00000000 fc:00 2372 /system/lib64/android.hardware.neuralnetworks@1.0.so
+7062077000-7062095000 ---p 00000000 00:00 0
+7062095000-706209b000 r--p 0003a000 fc:00 2372 /system/lib64/android.hardware.neuralnetworks@1.0.so
+706209b000-706209c000 rw-p 00040000 fc:00 2372 /system/lib64/android.hardware.neuralnetworks@1.0.so
+70620a9000-70620c9000 rw-p 00000000 00:05 10269730 /dev/ashmem/dalvik-CompilerMetadata (deleted)
+70620c9000-70620e3000 r-xp 00000000 fc:00 2956 /system/lib64/android.hardware.neuralnetworks@1.1.so
+70620e3000-70620f4000 ---p 00000000 00:00 0
+70620f4000-70620f7000 r--p 0001d000 fc:00 2956 /system/lib64/android.hardware.neuralnetworks@1.1.so
+70620f7000-70620f8000 rw-p 00020000 fc:00 2956 /system/lib64/android.hardware.neuralnetworks@1.1.so
+706210b000-70621d0000 r-xp 00000000 fc:00 2387 /system/lib64/libneuralnetworks.so
+70621d0000-70621e3000 ---p 00000000 00:00 0
+70621e3000-70621e5000 r--p 000ce000 fc:00 2387 /system/lib64/libneuralnetworks.so
+70621e5000-70621e7000 rw-p 000d0000 fc:00 2387 /system/lib64/libneuralnetworks.so
+70621e7000-7062372000 rw-p 00000000 00:00 0 [anon:.bss]
+7062373000-7062395000 r--s 00000000 fc:00 274 /system/fonts/NotoSerifMyanmar-Bold.otf
+7062395000-7062398000 r-xp 00000000 fc:00 2937 /system/lib64/libjnigraphics.so
+7062398000-70623b4000 ---p 00000000 00:00 0
+70623b4000-70623b5000 r--p 0000f000 fc:00 2937 /system/lib64/libjnigraphics.so
+70623b5000-70623b6000 rw-p 00010000 fc:00 2937 /system/lib64/libjnigraphics.so
+70623c8000-70623e0000 r-xp 00000000 fc:00 2662 /system/lib64/libGLESv3.so
+70623e0000-70623f7000 ---p 00000000 00:00 0
+70623f7000-70623f8000 r--p 0001f000 fc:00 2662 /system/lib64/libGLESv3.so
+70623f8000-70623f9000 rw-p 00020000 fc:00 2662 /system/lib64/libGLESv3.so
+70623fc000-706241c000 rw-p 00000000 00:05 10269729 /dev/ashmem/dalvik-CompilerMetadata (deleted)
+706241c000-7062444000 r-xp 00000000 fc:00 2603 /system/lib64/libexif.so
+7062444000-706245f000 ---p 00000000 00:00 0
+706245f000-7062472000 r--p 0002d000 fc:00 2603 /system/lib64/libexif.so
+7062472000-7062473000 rw-p 00040000 fc:00 2603 /system/lib64/libexif.so
+7062474000-7062490000 r--s 00000000 fc:00 286 /system/fonts/NotoSansMongolian-Regular.ttf
+7062490000-7062491000 r-xp 00000000 fc:00 2357 /system/lib64/libasyncio.so
+7062491000-70624af000 ---p 00000000 00:00 0
+70624af000-70624b0000 r--p 0000f000 fc:00 2357 /system/lib64/libasyncio.so
+70624b0000-70624b1000 rw-p 00010000 fc:00 2357 /system/lib64/libasyncio.so
+70624b5000-70624cf000 r--s 00000000 fc:00 221 /system/fonts/NotoSansMyanmarUI-Bold.ttf
+70624cf000-7062508000 r-xp 00000000 fc:00 2401 /system/lib64/libmtp.so
+7062508000-7062522000 ---p 00000000 00:00 0
+7062522000-7062525000 r--p 0003d000 fc:00 2401 /system/lib64/libmtp.so
+7062525000-706252c000 rw-p 00040000 fc:00 2401 /system/lib64/libmtp.so
+7062530000-7062550000 rw-p 00000000 00:05 10269728 /dev/ashmem/dalvik-CompilerMetadata (deleted)
+7062550000-7062572000 r--s 00000000 fc:00 234 /system/fonts/NotoSerifMyanmar-Regular.otf
+7062572000-706259e000 r-xp 00000000 fc:00 2620 /system/lib64/libmediandk.so
+706259e000-70625b9000 ---p 00000000 00:00 0
+70625b9000-70625bc000 r--p 0002d000 fc:00 2620 /system/lib64/libmediandk.so
+70625bc000-70625c0000 rw-p 00030000 fc:00 2620 /system/lib64/libmediandk.so
+70625c2000-70625d1000 r-xp 00000000 fc:00 2613 /system/lib64/libmidi.so
+70625d1000-70625ef000 ---p 00000000 00:00 0
+70625ef000-70625f1000 r--p 0000e000 fc:00 2613 /system/lib64/libmidi.so
+70625f1000-70625f2000 rw-p 00010000 fc:00 2613 /system/lib64/libmidi.so
+7062600000-7062621000 r-xp 00000000 fc:00 2366 /system/lib64/libmediadrmmetrics_lite.so
+7062621000-706263d000 ---p 00000000 00:00 0
+706263d000-706263f000 r--p 0002e000 fc:00 2366 /system/lib64/libmediadrmmetrics_lite.so
+706263f000-7062640000 rw-p 00030000 fc:00 2366 /system/lib64/libmediadrmmetrics_lite.so
+706264b000-706266b000 rw-p 00000000 00:05 10269727 /dev/ashmem/dalvik-CompilerMetadata (deleted)
+706266b000-70626d4000 r-xp 00000000 fc:00 2727 /system/lib64/libmedia_jni.so
+70626d4000-70626eb000 ---p 00000000 00:00 0
+70626eb000-70626f2000 r--p 00069000 fc:00 2727 /system/lib64/libmedia_jni.so
+70626f2000-70626f3000 rw-p 00070000 fc:00 2727 /system/lib64/libmedia_jni.so
+7062703000-7062732000 r-xp 00000000 fc:00 2399 /system/lib64/libcamera2ndk.so
+7062732000-7062748000 ---p 00000000 00:00 0
+7062748000-706274b000 r--p 0003d000 fc:00 2399 /system/lib64/libcamera2ndk.so
+706274b000-7062750000 rw-p 00040000 fc:00 2399 /system/lib64/libcamera2ndk.so
+7062768000-7062788000 rw-p 00000000 00:05 10269726 /dev/ashmem/dalvik-CompilerMetadata (deleted)
+7062788000-70627ee000 r-xp 00000000 fc:00 2974 /system/lib64/android.hardware.drm@1.0.so
+70627ee000-7062805000 ---p 00000000 00:00 0
+7062805000-706280d000 r--p 00068000 fc:00 2974 /system/lib64/android.hardware.drm@1.0.so
+706280d000-706280e000 rw-p 00070000 fc:00 2974 /system/lib64/android.hardware.drm@1.0.so
+706281a000-706281b000 ---p 00000000 00:00 0 [anon:thread signal stack guard]
+706281b000-706281f000 rw-p 00000000 00:00 0 [anon:thread signal stack]
+706281f000-7062843000 r--s 00000000 fc:00 142 /system/fonts/NotoSansKhmer-VF.ttf
+7062843000-7062886000 r-xp 00000000 fc:00 2637 /system/lib64/android.hardware.drm@1.1.so
+7062886000-70628a5000 ---p 00000000 00:00 0
+70628a5000-70628ab000 r--p 0004a000 fc:00 2637 /system/lib64/android.hardware.drm@1.1.so
+70628ab000-70628ac000 rw-p 00050000 fc:00 2637 /system/lib64/android.hardware.drm@1.1.so
+70628b0000-70628b1000 ---p 00000000 00:00 0 [anon:thread signal stack guard]
+70628b1000-70628b5000 rw-p 00000000 00:00 0 [anon:thread signal stack]
+70628b5000-70628db000 r--s 00000000 fc:00 137 /system/fonts/NotoSansSinhala-Bold.ttf
+70628db000-7062907000 r-xp 00000000 fc:00 2478 /system/lib64/libmediadrm.so
+7062907000-7062918000 ---p 00000000 00:00 0
+7062918000-7062920000 r--p 00038000 fc:00 2478 /system/lib64/libmediadrm.so
+7062920000-7062921000 rw-p 00040000 fc:00 2478 /system/lib64/libmediadrm.so
+7062922000-7062929000 rw-p 00000000 fc:00 583 /system/etc/event-log-tags
+7062929000-7062951000 r--s 00000000 fc:00 296 /system/fonts/NotoSansSinhala-Regular.ttf
+7062951000-7062997000 r-xp 00000000 fc:00 2448 /system/lib64/libaaudio.so
+7062997000-70629ac000 ---p 00000000 00:00 0
+70629ac000-70629b2000 r--p 0004a000 fc:00 2448 /system/lib64/libaaudio.so
+70629b2000-70629ba000 rw-p 00050000 fc:00 2448 /system/lib64/libaaudio.so
+70629ba000-70629bb000 ---p 00000000 00:00 0 [anon:thread signal stack guard]
+70629bb000-70629bf000 rw-p 00000000 00:00 0 [anon:thread signal stack]
+70629bf000-70629c0000 ---p 00000000 00:00 0 [anon:bionic TLS guard]
+70629c0000-70629c3000 rw-p 00000000 00:00 0 [anon:bionic TLS]
+70629c3000-70629c4000 ---p 00000000 00:00 0 [anon:bionic TLS guard]
+70629c4000-70629c5000 ---p 00000000 00:00 0 [anon:thread signal stack guard]
+70629c5000-70629c9000 rw-p 00000000 00:00 0 [anon:thread signal stack]
+70629c9000-70629e3000 r-xp 00000000 fc:00 2940 /system/lib64/libandroid.so
+70629e3000-70629f3000 ---p 00000000 00:00 0
+70629f3000-70629f6000 r--p 0001d000 fc:00 2940 /system/lib64/libandroid.so
+70629f6000-70629f7000 rw-p 00020000 fc:00 2940 /system/lib64/libandroid.so
+70629f8000-70629f9000 ---p 00000000 00:00 0 [anon:bionic TLS guard]
+70629f9000-70629fc000 rw-p 00000000 00:00 0 [anon:bionic TLS]
+70629fc000-70629fd000 ---p 00000000 00:00 0 [anon:bionic TLS guard]
+70629fd000-7062a3e000 r--s 00000000 fc:00 216 /system/fonts/NotoSerif-BoldItalic.ttf
+7062a3e000-7062b06000 rw-p 00000000 00:05 10270984 /dev/ashmem/dalvik-indirect ref table (deleted)
+7062b06000-7062bce000 rw-p 00000000 00:05 10270983 /dev/ashmem/dalvik-indirect ref table (deleted)
+7062bce000-7062dce000 rw-p 00000000 00:05 10270726 /dev/ashmem/dalvik-rb copying gc mark stack (deleted)
+7062dce000-70635ce000 rw-p 00000000 00:05 10270725 /dev/ashmem/dalvik-concurrent copying gc mark stack (deleted)
+70635ce000-7063dcf000 rw-p 00000000 00:05 10270724 /dev/ashmem/dalvik-live stack (deleted)
+7063dcf000-70645d0000 rw-p 00000000 00:05 10270723 /dev/ashmem/dalvik-allocation stack (deleted)
+70645d0000-70649d1000 rw-p 00000000 00:05 10270721 /dev/ashmem/dalvik-card table (deleted)
+70649d1000-7064ad1000 rw-p 00000000 00:05 10267648 /dev/ashmem/dalvik-large object free list space allocation info map (deleted)
+7064ad1000-7065ad1000 rw-p 00000000 00:05 10267644 /dev/ashmem/dalvik-region space live bitmap (deleted)
+7065ad1000-7065bd1000 rw-p 00000000 00:05 10267642 /dev/ashmem/dalvik-allocspace zygote / non moving space mark-bitmap 0 (deleted)
+7065bd1000-7065cd1000 rw-p 00000000 00:05 10267641 /dev/ashmem/dalvik-allocspace zygote / non moving space live-bitmap 0 (deleted)
+7065cd1000-7065cd2000 r-xp 00000000 fc:00 2946 /system/lib64/libsigchain.so
+7065cd2000-7065cf0000 ---p 00000000 00:00 0
+7065cf0000-7065cf1000 r--p 0000f000 fc:00 2946 /system/lib64/libsigchain.so
+7065cf1000-7065cf2000 rw-p 00010000 fc:00 2946 /system/lib64/libsigchain.so
+7065cf4000-7065d0f000 r--s 00000000 fc:00 190 /system/fonts/NotoSansMyanmar-Bold.ttf
+7065d0f000-7065d22000 r-xp 00000000 fc:00 2405 /system/lib64/liblz4.so
+7065d22000-7065d3e000 ---p 00000000 00:00 0
+7065d3e000-7065d3f000 r--p 0001f000 fc:00 2405 /system/lib64/liblz4.so
+7065d3f000-7065d40000 rw-p 00020000 fc:00 2405 /system/lib64/liblz4.so
+7065d40000-7065d5a000 r--s 00000000 fc:00 222 /system/fonts/NotoSansMyanmarUI-Regular.ttf
+7065d5a000-7065d5e000 r-xp 00000000 fc:00 2609 /system/lib64/libtombstoned_client.so
+7065d5e000-7065d79000 ---p 00000000 00:00 0
+7065d79000-7065d7a000 r--p 0000f000 fc:00 2609 /system/lib64/libtombstoned_client.so
+7065d7a000-7065d7b000 rw-p 00010000 fc:00 2609 /system/lib64/libtombstoned_client.so
+7065d7f000-7065d80000 ---p 00000000 00:00 0 [anon:thread signal stack guard]
+7065d80000-7065d84000 rw-p 00000000 00:00 0 [anon:thread signal stack]
+7065d84000-706636e000 r-xp 00000000 fc:00 2671 /system/lib64/libart.so
+706636e000-706638d000 ---p 00000000 00:00 0
+706638d000-706639e000 r--p 005ef000 fc:00 2671 /system/lib64/libart.so
+706639e000-70663a1000 rw-p 00600000 fc:00 2671 /system/lib64/libart.so
+70663a1000-70663a4000 rw-p 00000000 00:00 0 [anon:.bss]
+70663a6000-70663c6000 rw-p 00000000 00:05 10269725 /dev/ashmem/dalvik-CompilerMetadata (deleted)
+70663c6000-70663c8000 r-xp 00000000 fc:00 2673 /system/lib64/libmetricslogger.so
+70663c8000-70663e5000 ---p 00000000 00:00 0
+70663e5000-70663e6000 r--p 0000f000 fc:00 2673 /system/lib64/libmetricslogger.so
+70663e6000-70663e7000 rw-p 00010000 fc:00 2673 /system/lib64/libmetricslogger.so
+70663e7000-7066400000 r--s 00000000 fc:00 110 /system/fonts/NotoSansLepcha-Regular.ttf
+7066400000-7066800000 rw-p 00000000 00:00 0 [anon:libc_malloc]
+7066803000-706681e000 r--s 00000000 fc:00 297 /system/fonts/NotoSansMyanmar-Regular.ttf
+706681e000-7066821000 r--p 00000000 00:00 0 [anon:cfi shadow]
+7066821000-7066822000 r--p 00000000 00:00 0 [anon:cfi shadow]
+7066822000-7066b1d000 r--p 00000000 00:00 0 [anon:cfi shadow]
+7066b1d000-7066b1e000 r--p 00000000 00:00 0 [anon:cfi shadow]
+7066b1e000-7066ba0000 r--p 00000000 00:00 0 [anon:cfi shadow]
+7066ba0000-7066ba1000 r--p 00000000 00:00 0 [anon:cfi shadow]
+7066ba1000-7066ba2000 r--p 00000000 00:00 0 [anon:cfi shadow]
+7066ba2000-7066ba5000 r--p 00000000 00:00 0 [anon:cfi shadow]
+7066ba5000-7066ba6000 r--p 00000000 00:00 0 [anon:cfi shadow]
+7066ba6000-70e681e000 r--p 00000000 00:00 0 [anon:cfi shadow]
+70e681e000-70e6854000 r-xp 00000000 fc:00 2431 /system/lib64/libstagefright_foundation.so
+70e6854000-70e6865000 ---p 00000000 00:00 0
+70e6865000-70e6867000 r--p 0003e000 fc:00 2431 /system/lib64/libstagefright_foundation.so
+70e6867000-70e686c000 rw-p 00040000 fc:00 2431 /system/lib64/libstagefright_foundation.so
+70e686d000-70e686e000 ---p 00000000 00:00 0 [anon:bionic TLS guard]
+70e686e000-70e6871000 rw-p 00000000 00:00 0 [anon:bionic TLS]
+70e6871000-70e6873000 ---p 00000000 00:00 0 [anon:bionic TLS guard]
+70e6873000-70e6876000 rw-p 00000000 00:00 0 [anon:bionic TLS]
+70e6876000-70e6877000 ---p 00000000 00:00 0 [anon:bionic TLS guard]
+70e6877000-70e688c000 r--s 00000000 fc:00 301 /system/fonts/NotoSansSinhalaUI-Bold.otf
+70e688c000-70e688e000 r-xp 00000000 fc:00 2943 /system/lib64/libion.so
+70e688e000-70e68ab000 ---p 00000000 00:00 0
+70e68ab000-70e68ac000 r--p 0000f000 fc:00 2943 /system/lib64/libion.so
+70e68ac000-70e68ad000 rw-p 00010000 fc:00 2943 /system/lib64/libion.so
+70e68ad000-70e68af000 rw-p 00000000 00:05 10282496 /dev/ashmem/dalvik-indirect ref table (deleted)
+70e68af000-70e68b1000 rw-p 00000000 00:05 10282493 /dev/ashmem/dalvik-indirect ref table (deleted)
+70e68b1000-70e68ee000 r--s 00000000 fc:00 256 /system/fonts/NotoSerif-Italic.ttf
+70e68ee000-70e6910000 r-xp 00000000 fc:00 2502 /system/lib64/libhidlbase.so
+70e6910000-70e692c000 ---p 00000000 00:00 0
+70e692c000-70e692e000 r--p 0002e000 fc:00 2502 /system/lib64/libhidlbase.so
+70e692e000-70e692f000 rw-p 00030000 fc:00 2502 /system/lib64/libhidlbase.so
+70e6930000-70e693f000 r--s 00000000 fc:00 1082 /system/usr/hyphen-data/hyph-en-us.hyb
+70e693f000-70e6954000 r--s 00000000 fc:00 138 /system/fonts/NotoSansSinhalaUI-Regular.otf
+70e6954000-70e6978000 r-xp 00000000 fc:00 2482 /system/lib64/libui.so
+70e6978000-70e6992000 ---p 00000000 00:00 0
+70e6992000-70e6994000 r--p 0002e000 fc:00 2482 /system/lib64/libui.so
+70e6994000-70e6995000 rw-p 00030000 fc:00 2482 /system/lib64/libui.so
+70e6996000-70e69a2000 r--s 00000000 fc:00 1117 /system/usr/hyphen-data/hyph-en-gb.hyb
+70e69a2000-70e69b7000 r--s 00000000 fc:00 202 /system/fonts/NotoSerifSinhala-Bold.otf
+70e69b7000-70e69cb000 r--s 00000000 fc:00 124 /system/fonts/NotoSansOriyaUI-Bold.ttf
+70e69cb000-70e69e1000 r-xp 00000000 fc:00 2537 /system/lib64/liblog.so
+70e69e1000-70e69fa000 ---p 00000000 00:00 0
+70e69fa000-70e69fb000 r--p 0001f000 fc:00 2537 /system/lib64/liblog.so
+70e69fb000-70e69fc000 rw-p 00020000 fc:00 2537 /system/lib64/liblog.so
+70e69fc000-70e69fe000 rw-p 00000000 00:05 10266158 /dev/ashmem/dalvik-indirect ref table (deleted)
+70e69fe000-70e69ff000 ---p 00000000 00:00 0 [anon:bionic TLS guard]
+70e69ff000-70e6a02000 rw-p 00000000 00:00 0 [anon:bionic TLS]
+70e6a02000-70e6a03000 ---p 00000000 00:00 0 [anon:bionic TLS guard]
+70e6a03000-70e6a05000 r-xp 00000000 fc:00 2489 /system/lib64/android.hidl.token@1.0-utils.so
+70e6a05000-70e6a22000 ---p 00000000 00:00 0
+70e6a22000-70e6a23000 r--p 0000f000 fc:00 2489 /system/lib64/android.hidl.token@1.0-utils.so
+70e6a23000-70e6a24000 rw-p 00010000 fc:00 2489 /system/lib64/android.hidl.token@1.0-utils.so
+70e6a25000-70e6a2e000 r--s 00000000 fc:00 1120 /system/usr/hyphen-data/hyph-ga.hyb
+70e6a2e000-70e6a42000 r--s 00000000 fc:00 109 /system/fonts/NotoSansOriyaUI-Regular.ttf
+70e6a42000-70e6a59000 r-xp 00000000 fc:00 2446 /system/lib64/android.hardware.graphics.mapper@2.0.so
+70e6a59000-70e6a6e000 ---p 00000000 00:00 0
+70e6a6e000-70e6a70000 r--p 0001e000 fc:00 2446 /system/lib64/android.hardware.graphics.mapper@2.0.so
+70e6a70000-70e6a71000 rw-p 00020000 fc:00 2446 /system/lib64/android.hardware.graphics.mapper@2.0.so
+70e6a72000-70e6a78000 r--s 00000000 fc:00 1084 /system/usr/hyphen-data/hyph-et.hyb
+70e6a78000-70e6a9d000 r--s 00000000 fc:00 207 /system/fonts/NotoSerifTelugu-Bold.ttf
+70e6a9d000-70e6a9f000 r-xp 00000000 fc:00 2330 /system/lib64/android.hardware.configstore-utils.so
+70e6a9f000-70e6abc000 ---p 00000000 00:00 0
+70e6abc000-70e6abd000 r--p 0000f000 fc:00 2330 /system/lib64/android.hardware.configstore-utils.so
+70e6abd000-70e6abe000 rw-p 00010000 fc:00 2330 /system/lib64/android.hardware.configstore-utils.so
+70e6abe000-70e6ac0000 r--s f8042000 00:10 20630 /dev/kgsl-3d0
+70e6ac0000-70e6adc000 r--s 00000000 fc:00 172 /system/fonts/NotoSansTeluguUI-Bold.ttf
+70e6adc000-70e6ae0000 r-xp 00000000 fc:00 2555 /system/lib64/libstagefright_omx_utils.so
+70e6ae0000-70e6afb000 ---p 00000000 00:00 0
+70e6afb000-70e6afc000 r--p 0000f000 fc:00 2555 /system/lib64/libstagefright_omx_utils.so
+70e6afc000-70e6afd000 rw-p 00010000 fc:00 2555 /system/lib64/libstagefright_omx_utils.so
+70e6afd000-70e6afe000 ---p 00000000 00:00 0 [anon:thread signal stack guard]
+70e6afe000-70e6b02000 rw-p 00000000 00:00 0 [anon:thread signal stack]
+70e6b02000-70e6b27000 r--s 00000000 fc:00 271 /system/fonts/NotoSerifTelugu-Regular.ttf
+70e6b27000-70e6b61000 r-xp 00000000 fc:00 2695 /system/lib64/libdexfile.so
+70e6b61000-70e6b73000 ---p 00000000 00:00 0
+70e6b73000-70e6b75000 r--p 0003e000 fc:00 2695 /system/lib64/libdexfile.so
+70e6b75000-70e6b76000 rw-p 00040000 fc:00 2695 /system/lib64/libdexfile.so
+70e6b76000-70e6b78000 rw-p 00000000 00:05 10253452 /dev/ashmem/dalvik-indirect ref table (deleted)
+70e6b78000-70e6b85000 r--s 00000000 fc:00 1080 /system/usr/hyphen-data/hyph-cu.hyb
+70e6b85000-70e6b96000 r-xp 00000000 fc:00 2957 /system/lib64/libaudioutils.so
+70e6b96000-70e6bb4000 ---p 00000000 00:00 0
+70e6bb4000-70e6bb5000 r--p 0001f000 fc:00 2957 /system/lib64/libaudioutils.so
+70e6bb5000-70e6bb6000 rw-p 00020000 fc:00 2957 /system/lib64/libaudioutils.so
+70e6bb6000-70e6bb7000 ---p 00000000 00:00 0 [anon:bionic TLS guard]
+70e6bb7000-70e6bba000 rw-p 00000000 00:00 0 [anon:bionic TLS]
+70e6bba000-70e6bbb000 ---p 00000000 00:00 0 [anon:bionic TLS guard]
+70e6bbb000-70e6bd7000 r--s 00000000 fc:00 132 /system/fonts/NotoSansTeluguUI-Regular.ttf
+70e6bd7000-70e6bdc000 r-xp 00000000 fc:00 2409 /system/lib64/libprocessgroup.so
+70e6bdc000-70e6bf6000 ---p 00000000 00:00 0
+70e6bf6000-70e6bf7000 r--p 0000f000 fc:00 2409 /system/lib64/libprocessgroup.so
+70e6bf7000-70e6bf8000 rw-p 00010000 fc:00 2409 /system/lib64/libprocessgroup.so
+70e6bf8000-70e6c09000 r--s 00000000 fc:00 79 /system/fonts/NotoSansNewa-Regular.otf
+70e6c09000-70e6c1c000 r-xp 00000000 fc:00 2329 /system/lib64/android.hidl.memory.token@1.0.so
+70e6c1c000-70e6c36000 ---p 00000000 00:00 0
+70e6c36000-70e6c38000 r--p 0001e000 fc:00 2329 /system/lib64/android.hidl.memory.token@1.0.so
+70e6c38000-70e6c39000 rw-p 00020000 fc:00 2329 /system/lib64/android.hidl.memory.token@1.0.so
+70e6c3a000-70e6c4f000 r--s 00000000 fc:00 253 /system/fonts/NotoSansOriya-Bold.ttf
+70e6c4f000-70e6c6b000 r-xp 00000000 fc:00 2407 /system/lib64/libutils.so
+70e6c6b000-70e6c7e000 ---p 00000000 00:00 0
+70e6c7e000-70e6c7f000 r--p 0001f000 fc:00 2407 /system/lib64/libutils.so
+70e6c7f000-70e6c80000 rw-p 00020000 fc:00 2407 /system/lib64/libutils.so
+70e6c80000-70e6c9d000 r-xp 00000000 fc:00 2934 /system/lib64/libtinyxml2.so
+70e6c9d000-70e6cba000 ---p 00000000 00:00 0
+70e6cba000-70e6cbc000 r--p 0001e000 fc:00 2934 /system/lib64/libtinyxml2.so
+70e6cbc000-70e6cbf000 rw-p 00020000 fc:00 2934 /system/lib64/libtinyxml2.so
+70e6cbf000-70e6ccf000 r--s 00000000 fc:00 80 /system/fonts/NotoSansMarchen-Regular.otf
+70e6ccf000-70e6ce0000 r-xp 00000000 fc:00 2655 /system/lib64/libbase.so
+70e6ce0000-70e6cfe000 ---p 00000000 00:00 0
+70e6cfe000-70e6cff000 r--p 0001f000 fc:00 2655 /system/lib64/libbase.so
+70e6cff000-70e6d00000 rw-p 00020000 fc:00 2655 /system/lib64/libbase.so
+70e6d00000-70e6d09000 r--s 00000000 fc:00 1113 /system/usr/hyphen-data/hyph-cy.hyb
+70e6d09000-70e6d50000 r-xp 00000000 fc:00 2495 /system/lib64/libRScpp.so
+70e6d50000-70e6d68000 ---p 00000000 00:00 0
+70e6d68000-70e6d69000 r--p 0004f000 fc:00 2495 /system/lib64/libRScpp.so
+70e6d69000-70e6d6a000 rw-p 00050000 fc:00 2495 /system/lib64/libRScpp.so
+70e6d6b000-70e6d6d000 r--s 00088000 103:1d 1736830 /data/app/com.google.sample.tunnel-HGGRU03Gu1Mwkf_-RnFmvw==/base.apk
+70e6d6d000-70e6d7d000 r--s 00000000 fc:00 238 /system/fonts/NotoSansVai-Regular.ttf
+70e6d7d000-70e6d98000 r--s 00000000 fc:00 276 /system/fonts/NotoSansTelugu-Bold.ttf
+70e6d98000-70e6f2b000 r-xp 00000000 fc:00 2961 /system/lib64/libicuuc.so
+70e6f2b000-70e6f47000 ---p 00000000 00:00 0
+70e6f47000-70e6f5c000 r--p 0019b000 fc:00 2961 /system/lib64/libicuuc.so
+70e6f5c000-70e6f5d000 rw-p 001b0000 fc:00 2961 /system/lib64/libicuuc.so
+70e6f5d000-70e6f5e000 rw-p 00000000 00:00 0 [anon:.bss]
+70e6f5f000-70e6f68000 r--s 00000000 fc:00 159 /system/fonts/NotoSansLinearA-Regular.otf
+70e6f68000-70e6f84000 r--s 00000000 fc:00 170 /system/fonts/NotoSansTelugu-Regular.ttf
+70e6f84000-70e7058000 r-xp 00000000 fc:00 2356 /system/lib64/libc.so
+70e7058000-70e706e000 ---p 00000000 00:00 0
+70e706e000-70e7074000 r--p 000da000 fc:00 2356 /system/lib64/libc.so
+70e7074000-70e7076000 rw-p 000e0000 fc:00 2356 /system/lib64/libc.so
+70e7076000-70e7077000 rw-p 00000000 00:00 0 [anon:.bss]
+70e7077000-70e7078000 r--p 00000000 00:00 0 [anon:.bss]
+70e7078000-70e7080000 rw-p 00000000 00:00 0 [anon:.bss]
+70e7080000-70e7087000 r--s 00000000 fc:00 102 /system/fonts/NotoSansSharada-Regular.otf
+70e7087000-70e708e000 r-xp 00000000 fc:00 2378 /system/lib64/libheif.so
+70e708e000-70e70a4000 ---p 00000000 00:00 0
+70e70a4000-70e70a6000 r--p 0000e000 fc:00 2378 /system/lib64/libheif.so
+70e70a6000-70e70a7000 rw-p 00010000 fc:00 2378 /system/lib64/libheif.so
+70e70a7000-70e70a9000 r--s 00000000 fc:00 1116 /system/usr/hyphen-data/hyph-sl.hyb
+70e70a9000-70e70ab000 r--s 00000000 fc:00 1147 /system/usr/hyphen-data/hyph-mn-cyrl.hyb
+70e70ab000-70e70c5000 r--s 00000000 fc:00 291 /system/fonts/NotoSansBengaliUI-Bold.ttf
+70e70c5000-70e70ea000 r-xp 00000000 fc:00 2545 /system/lib64/libEGL.so
+70e70ea000-70e7109000 ---p 00000000 00:00 0
+70e7109000-70e710d000 r--p 0002c000 fc:00 2545 /system/lib64/libEGL.so
+70e710d000-70e710e000 rw-p 00030000 fc:00 2545 /system/lib64/libEGL.so
+70e710e000-70e7115000 rw-p 00000000 00:00 0 [anon:.bss]
+70e7115000-70e7119000 r--s 00000000 fc:00 1143 /system/usr/hyphen-data/hyph-es.hyb
+70e7119000-70e712e000 r--s 00000000 fc:00 71 /system/fonts/NotoSansOriya-Regular.ttf
+70e712e000-70e717a000 r--s 00000000 fc:00 272 /system/fonts/Roboto-Thin.ttf
+70e717a000-70e71db000 r-xp 00000000 fc:00 2393 /system/lib64/libpdx_default_transport.so
+70e71db000-70e71f7000 ---p 00000000 00:00 0
+70e71f7000-70e71f9000 r--p 0006e000 fc:00 2393 /system/lib64/libpdx_default_transport.so
+70e71f9000-70e71fa000 rw-p 00070000 fc:00 2393 /system/lib64/libpdx_default_transport.so
+70e71fa000-70e71fb000 rw-p 00000000 00:00 0 [anon:.bss]
+70e71fc000-70e71fe000 r--s 00000000 fc:00 1107 /system/usr/hyphen-data/hyph-fr.hyb
+70e71fe000-70e7200000 r--s 00000000 fc:00 1097 /system/usr/hyphen-data/hyph-da.hyb
+70e7200000-70e7223000 r-xp 00000000 fc:00 2380 /system/lib64/libminikin.so
+70e7223000-70e723e000 ---p 00000000 00:00 0
+70e723e000-70e723f000 r--p 0002f000 fc:00 2380 /system/lib64/libminikin.so
+70e723f000-70e7240000 rw-p 00030000 fc:00 2380 /system/lib64/libminikin.so
+70e7241000-70e724d000 r--s 00000000 fc:00 179 /system/fonts/NotoSansTaiTham-Regular.ttf
+70e724d000-70e725c000 r-xp 00000000 fc:00 2527 /system/lib64/libmediautils.so
+70e725c000-70e7279000 ---p 00000000 00:00 0
+70e7279000-70e727b000 r--p 0001e000 fc:00 2527 /system/lib64/libmediautils.so
+70e727b000-70e727c000 rw-p 00020000 fc:00 2527 /system/lib64/libmediautils.so
+70e727d000-70e7283000 r--s 00000000 fc:00 136 /system/fonts/NotoSansMiao-Regular.otf
+70e7283000-70e74d2000 r-xp 00000000 fc:00 2349 /system/lib64/libicui18n.so
+70e74d2000-70e74e6000 ---p 00000000 00:00 0
+70e74e6000-70e74fa000 r--p 0025c000 fc:00 2349 /system/lib64/libicui18n.so
+70e74fa000-70e74fb000 rw-p 00270000 fc:00 2349 /system/lib64/libicui18n.so
+70e74fc000-70e74ff000 r--s 00000000 103:1d 1474562 /data/resource-cache/vendor@overlay@framework-res__auto_generated_rro.apk@idmap
+70e74ff000-70e750c000 r--s 00000000 fc:00 126 /system/fonts/NotoSansSyriacWestern-Regular.ttf
+70e750c000-70e751b000 r-xp 00000000 fc:00 2466 /system/lib64/libmediaextractor.so
+70e751b000-70e753a000 ---p 00000000 00:00 0
+70e753a000-70e753b000 r--p 0000f000 fc:00 2466 /system/lib64/libmediaextractor.so
+70e753b000-70e753c000 rw-p 00010000 fc:00 2466 /system/lib64/libmediaextractor.so
+70e753d000-70e7540000 r--s 00000000 fc:00 107 /system/fonts/NotoSansPauCinHau-Regular.otf
+70e7540000-70e7593000 r-xp 00000000 fc:00 2363 /system/lib64/libandroidfw.so
+70e7593000-70e75ac000 ---p 00000000 00:00 0
+70e75ac000-70e75af000 r--p 0005d000 fc:00 2363 /system/lib64/libandroidfw.so
+70e75af000-70e75b0000 rw-p 00060000 fc:00 2363 /system/lib64/libandroidfw.so
+70e75b0000-70e75b2000 r--s 00000000 fc:00 1083 /system/usr/hyphen-data/hyph-be.hyb
+70e75b2000-70e75cd000 r--s 00000000 fc:00 270 /system/fonts/NotoSansBengaliUI-Regular.ttf
+70e75cd000-70e75cf000 r-xp 00000000 fc:00 2701 /system/lib64/libmemtrack.so
+70e75cf000-70e75ec000 ---p 00000000 00:00 0
+70e75ec000-70e75ed000 r--p 0000f000 fc:00 2701 /system/lib64/libmemtrack.so
+70e75ed000-70e75ee000 rw-p 00010000 fc:00 2701 /system/lib64/libmemtrack.so
+70e75ee000-70e75f0000 r--s 00000000 fc:00 209 /system/fonts/NotoSansSoraSompeng-Regular.otf
+70e75f0000-70e760d000 r--s 00000000 fc:00 243 /system/fonts/NotoSerifBengali-Bold.ttf
+70e760d000-70e7613000 r-xp 00000000 fc:00 2667 /system/lib64/libutilscallstack.so
+70e7613000-70e762c000 ---p 00000000 00:00 0
+70e762c000-70e762d000 r--p 0000f000 fc:00 2667 /system/lib64/libutilscallstack.so
+70e762d000-70e762e000 rw-p 00010000 fc:00 2667 /system/lib64/libutilscallstack.so
+70e762e000-70e7632000 r--s 00000000 fc:00 99 /system/fonts/NotoSansPahawhHmong-Regular.otf
+70e7632000-70e764f000 r--s 00000000 fc:00 205 /system/fonts/NotoSerifBengali-Regular.ttf
+70e764f000-70e7661000 r-xp 00000000 fc:00 2710 /system/lib64/libcutils.so
+70e7661000-70e767d000 ---p 00000000 00:00 0
+70e767d000-70e767f000 r--p 0001e000 fc:00 2710 /system/lib64/libcutils.so
+70e767f000-70e7680000 rw-p 00020000 fc:00 2710 /system/lib64/libcutils.so
+70e7680000-70e7683000 r--s 00000000 fc:00 257 /system/fonts/NotoSansPalmyrene-Regular.otf
+70e7683000-70e7697000 r--s 00000000 fc:00 78 /system/fonts/NotoSansKannadaUI-Bold.ttf
+70e7697000-70e769a000 r-xp 00000000 fc:00 2362 /system/lib64/libstagefright_http_support.so
+70e769a000-70e76b6000 ---p 00000000 00:00 0
+70e76b6000-70e76b7000 r--p 0000f000 fc:00 2362 /system/lib64/libstagefright_http_support.so
+70e76b7000-70e76b8000 rw-p 00010000 fc:00 2362 /system/lib64/libstagefright_http_support.so
+70e76b8000-70e76b9000 rw-p 00000000 00:00 0 [anon:linker_alloc_lob]
+70e76b9000-70e76be000 r--s 00000000 fc:00 165 /system/fonts/NotoSansMeroitic-Regular.otf
+70e76be000-70e76cb000 r--s 00000000 fc:00 112 /system/fonts/NotoSansSyriacEastern-Regular.ttf
+70e76cb000-70e76de000 r-xp 00000000 fc:00 2343 /system/lib64/libsensor.so
+70e76de000-70e76f5000 ---p 00000000 00:00 0
+70e76f5000-70e76f8000 r--p 0001d000 fc:00 2343 /system/lib64/libsensor.so
+70e76f8000-70e76f9000 rw-p 00020000 fc:00 2343 /system/lib64/libsensor.so
+70e76f9000-70e76fc000 r--s 00000000 fc:00 157 /system/fonts/NotoSansOldPermic-Regular.otf
+70e76fc000-70e7708000 r--s 00000000 fc:00 189 /system/fonts/NotoSansSyriacEstrangela-Regular.ttf
+70e7708000-70e771d000 r-xp 00000000 fc:00 2339 /system/lib64/android.hidl.token@1.0.so
+70e771d000-70e7735000 ---p 00000000 00:00 0
+70e7735000-70e7737000 r--p 0001e000 fc:00 2339 /system/lib64/android.hidl.token@1.0.so
+70e7737000-70e7738000 rw-p 00020000 fc:00 2339 /system/lib64/android.hidl.token@1.0.so
+70e7738000-70e7739000 r--p 00000000 00:00 0 [anon:linker_alloc]
+70e7739000-70e773b000 r--s 00000000 fc:00 267 /system/fonts/NotoSansOldNorthArabian-Regular.otf
+70e773b000-70e7740000 r--s 00000000 fc:00 208 /system/fonts/NotoSansManichaean-Regular.otf
+70e7740000-70e775c000 r--s 00000000 fc:00 118 /system/fonts/NotoSansGujaratiUI-Bold.ttf
+70e775c000-70e7767000 r-xp 00000000 fc:00 2525 /system/lib64/libappfuse.so
+70e7767000-70e777b000 ---p 00000000 00:00 0
+70e777b000-70e777c000 r--p 0000f000 fc:00 2525 /system/lib64/libappfuse.so
+70e777c000-70e777d000 rw-p 00010000 fc:00 2525 /system/lib64/libappfuse.so
+70e777e000-70e7795000 r--s 00000000 fc:00 250 /system/fonts/NotoSerifKannada-Bold.ttf
+70e7795000-70e7798000 r-xp 00000000 fc:00 2413 /system/lib64/libpackagelistparser.so
+70e7798000-70e77b4000 ---p 00000000 00:00 0
+70e77b4000-70e77b5000 r--p 0000f000 fc:00 2413 /system/lib64/libpackagelistparser.so
+70e77b5000-70e77b6000 rw-p 00010000 fc:00 2413 /system/lib64/libpackagelistparser.so
+70e77b6000-70e77b8000 r--s 00000000 fc:00 147 /system/fonts/NotoSansNabataean-Regular.otf
+70e77b8000-70e77ba000 r--s 00000000 fc:00 146 /system/fonts/NotoSansMultani-Regular.otf
+70e77ba000-70e77c1000 r--s 00000000 fc:00 214 /system/fonts/NotoSansPhagsPa-Regular.ttf
+70e77c1000-70e77de000 r--s 00000000 fc:00 90 /system/fonts/NotoSansGujaratiUI-Regular.ttf
+70e77de000-70e77e0000 r-xp 00000000 fc:00 2430 /system/lib64/libdl.so
+70e77e0000-70e77fd000 ---p 00000000 00:00 0
+70e77fd000-70e77fe000 r--p 0000f000 fc:00 2430 /system/lib64/libdl.so
+70e77fe000-70e77ff000 r--p 00000000 00:00 0 [anon:.bss]
+70e7800000-70e7809000 r--s 00000000 fc:00 258 /system/fonts/NotoSansSymbols-Regular-Subsetted2.ttf
+70e7809000-70e7857000 r-xp 00000000 fc:00 2560 /system/lib64/libjpeg.so
+70e7857000-70e7868000 ---p 00000000 00:00 0
+70e7868000-70e7869000 r--p 0004f000 fc:00 2560 /system/lib64/libjpeg.so
+70e7869000-70e786a000 rw-p 00050000 fc:00 2560 /system/lib64/libjpeg.so
+70e786a000-70e7887000 r--s 00000000 fc:00 237 /system/fonts/NotoSansGujarati-Bold.ttf
+70e7887000-70e788a000 r-xp 00000000 fc:00 2608 /system/lib64/libnetd_client.so
+70e788a000-70e78a6000 ---p 00000000 00:00 0
+70e78a6000-70e78a7000 r--p 0000f000 fc:00 2608 /system/lib64/libnetd_client.so
+70e78a7000-70e78a8000 rw-p 00010000 fc:00 2608 /system/lib64/libnetd_client.so
+70e78a8000-70e78aa000 r--s 00000000 fc:00 290 /system/fonts/NotoSansMro-Regular.otf
+70e78aa000-70e78b9000 r--s 00000000 fc:00 84 /system/fonts/NotoSansLinearB-Regular.ttf
+70e78b9000-70e78d7000 r--s 00000000 fc:00 287 /system/fonts/NotoSansGujarati-Regular.ttf
+70e78d7000-70e78d8000 r-xp 00000000 fc:00 2651 /system/lib64/libvndksupport.so
+70e78d8000-70e78f6000 ---p 00000000 00:00 0
+70e78f6000-70e78f7000 r--p 0000f000 fc:00 2651 /system/lib64/libvndksupport.so
+70e78f7000-70e78f8000 rw-p 00010000 fc:00 2651 /system/lib64/libvndksupport.so
+70e78f9000-70e78fc000 r--s 00000000 fc:00 178 /system/fonts/NotoSansTaiLe-Regular.ttf
+70e78fc000-70e7900000 r--s 00000000 fc:00 163 /system/fonts/NotoSansTifinagh-Regular.ttf
+70e7900000-70e7906000 r-xp 00000000 fc:00 2659 /system/lib64/libnativeloader.so
+70e7906000-70e791f000 ---p 00000000 00:00 0
+70e791f000-70e7920000 r--p 0000f000 fc:00 2659 /system/lib64/libnativeloader.so
+70e7920000-70e7921000 rw-p 00010000 fc:00 2659 /system/lib64/libnativeloader.so
+70e7921000-70e7923000 r--s 00000000 fc:00 268 /system/fonts/NotoSansHatran-Regular.otf
+70e7923000-70e7927000 r--s 00000000 fc:00 195 /system/fonts/NotoSansTaiViet-Regular.ttf
+70e7927000-70e7945000 r--s 00000000 fc:00 139 /system/fonts/NotoSansDevanagariUI-Bold.ttf
+70e7945000-70e79a3000 r-xp 00000000 fc:00 2450 /system/lib64/libharfbuzz_ng.so
+70e79a3000-70e79b3000 ---p 00000000 00:00 0
+70e79b3000-70e79b5000 r--p 0005e000 fc:00 2450 /system/lib64/libharfbuzz_ng.so
+70e79b5000-70e79b6000 rw-p 00060000 fc:00 2450 /system/lib64/libharfbuzz_ng.so
+70e79b6000-70e79c5000 r--s 00000000 fc:00 111 /system/fonts/NotoSansKaithi-Regular.ttf
+70e79c5000-70e7a92000 r-xp 00000000 fc:00 2332 /system/lib64/libc++.so
+70e7a92000-70e7aae000 ---p 00000000 00:00 0
+70e7aae000-70e7ab8000 r--p 000d6000 fc:00 2332 /system/lib64/libc++.so
+70e7ab8000-70e7ab9000 rw-p 000e0000 fc:00 2332 /system/lib64/libc++.so
+70e7ab9000-70e7abc000 rw-p 00000000 00:00 0 [anon:.bss]
+70e7abc000-70e7abe000 r--s 00000000 fc:00 73 /system/fonts/NotoSansBassaVah-Regular.otf
+70e7abe000-70e7ac8000 r--s 00000000 fc:00 254 /system/fonts/NotoSansJavanese-Regular.ttf
+70e7ac8000-70e7acb000 r-xp 00000000 fc:00 2660 /system/lib64/libnativebridge.so
+70e7acb000-70e7ae7000 ---p 00000000 00:00 0
+70e7ae7000-70e7ae8000 r--p 0000f000 fc:00 2660 /system/lib64/libnativebridge.so
+70e7ae8000-70e7ae9000 rw-p 00010000 fc:00 2660 /system/lib64/libnativebridge.so
+70e7ae9000-70e7aee000 r--s 00000000 fc:00 158 /system/fonts/NotoSansSaurashtra-Regular.ttf
+70e7aee000-70e7b0f000 r--s 00000000 fc:00 82 /system/fonts/NotoSansDevanagari-Bold.ttf
+70e7b0f000-70e7b2e000 r-xp 00000000 fc:00 2612 /system/lib64/libpcre2.so
+70e7b2e000-70e7b3e000 ---p 00000000 00:00 0
+70e7b3e000-70e7b3f000 r--p 0001f000 fc:00 2612 /system/lib64/libpcre2.so
+70e7b3f000-70e7b40000 rw-p 00020000 fc:00 2612 /system/lib64/libpcre2.so
+70e7b40000-70e7bcc000 r-xp 00000000 fc:00 2975 /system/lib64/libgui.so
+70e7bcc000-70e7be2000 ---p 00000000 00:00 0
+70e7be2000-70e7bf5000 r--p 0008d000 fc:00 2975 /system/lib64/libgui.so
+70e7bf5000-70e7bf6000 rw-p 000a0000 fc:00 2975 /system/lib64/libgui.so
+70e7bf6000-70e7bf7000 r--p 00000000 00:00 0 [anon:linker_alloc]
+70e7bf7000-70e7bf9000 r--s 00000000 fc:00 228 /system/fonts/NotoSansUgaritic-Regular.ttf
+70e7bf9000-70e7c08000 r--s 00000000 fc:00 89 /system/fonts/NotoSansCherokee-Regular.ttf
+70e7c08000-70e7dea000 r-xp 00000000 fc:00 2441 /system/lib64/libandroid_runtime.so
+70e7dea000-70e7e04000 ---p 00000000 00:00 0
+70e7e04000-70e7e23000 r--p 001e1000 fc:00 2441 /system/lib64/libandroid_runtime.so
+70e7e23000-70e7e24000 rw-p 00200000 fc:00 2441 /system/lib64/libandroid_runtime.so
+70e7e24000-70e7e28000 rw-p 00000000 00:00 0 [anon:.bss]
+70e7e29000-70e7e66000 r--s 00000000 fc:00 74 /system/fonts/NotoSerif-Bold.ttf
+70e7e66000-70e7ed0000 r-xp 00000000 fc:00 2547 /system/lib64/libclang_rt.ubsan_standalone-aarch64-android.so
+70e7ed0000-70e7edf000 ---p 00000000 00:00 0
+70e7edf000-70e7ee1000 r--p 00069000 fc:00 2547 /system/lib64/libclang_rt.ubsan_standalone-aarch64-android.so
+70e7ee1000-70e7ee4000 rw-p 0006b000 fc:00 2547 /system/lib64/libclang_rt.ubsan_standalone-aarch64-android.so
+70e7ee4000-70e89f6000 rw-p 00000000 00:00 0 [anon:.bss]
+70e89f6000-70e89fa000 r--s 00000000 fc:00 127 /system/fonts/NotoSansSylotiNagri-Regular.ttf
+70e89fa000-70e8a06000 r--s 00000000 fc:00 93 /system/fonts/NotoSansCanadianAboriginal-Regular.ttf
+70e8a06000-70e8a1b000 r-xp 00000000 fc:00 2460 /system/lib64/android.hardware.graphics.allocator@2.0.so
+70e8a1b000-70e8a33000 ---p 00000000 00:00 0
+70e8a33000-70e8a35000 r--p 0001e000 fc:00 2460 /system/lib64/android.hardware.graphics.allocator@2.0.so
+70e8a35000-70e8a36000 rw-p 00020000 fc:00 2460 /system/lib64/android.hardware.graphics.allocator@2.0.so
+70e8a36000-70e8a55000 r--s 00000000 fc:00 145 /system/fonts/NotoSansDevanagariUI-Regular.ttf
+70e8a55000-70e8a61000 r-xp 00000000 fc:00 2540 /system/lib64/libstagefright_xmlparser.so
+70e8a61000-70e8a74000 ---p 00000000 00:00 0
+70e8a74000-70e8a75000 r--p 0000f000 fc:00 2540 /system/lib64/libstagefright_xmlparser.so
+70e8a75000-70e8a76000 rw-p 00010000 fc:00 2540 /system/lib64/libstagefright_xmlparser.so
+70e8a76000-70e8a78000 r--s 00000000 fc:00 293 /system/fonts/NotoSansTagbanwa-Regular.ttf
+70e8a78000-70e8a8f000 r--s 00000000 fc:00 161 /system/fonts/NotoSerifKannada-Regular.ttf
+70e8a8f000-70e8b23000 r-xp 00000000 fc:00 2633 /system/lib64/libaudioclient.so
+70e8b23000-70e8b37000 ---p 00000000 00:00 0
+70e8b37000-70e8b49000 r--p 0009e000 fc:00 2633 /system/lib64/libaudioclient.so
+70e8b49000-70e8b55000 rw-p 000b0000 fc:00 2633 /system/lib64/libaudioclient.so
+70e8b55000-70e8b9f000 r--s 00000000 fc:00 83 /system/fonts/RobotoCondensed-Light.ttf
+70e8b9f000-70e8ba1000 r-xp 00000000 fc:00 2520 /system/lib64/libhardware_legacy.so
+70e8ba1000-70e8bbe000 ---p 00000000 00:00 0
+70e8bbe000-70e8bbf000 r--p 0000f000 fc:00 2520 /system/lib64/libhardware_legacy.so
+70e8bbf000-70e8bc0000 rw-p 00010000 fc:00 2520 /system/lib64/libhardware_legacy.so
+70e8bc0000-70e8be0000 r-xp 00000000 fc:00 2410 /system/lib64/android.hidl.memory@1.0.so
+70e8be0000-70e8bfa000 ---p 00000000 00:00 0
+70e8bfa000-70e8bfd000 r--p 0002d000 fc:00 2410 /system/lib64/android.hidl.memory@1.0.so
+70e8bfd000-70e8bfe000 rw-p 00030000 fc:00 2410 /system/lib64/android.hidl.memory@1.0.so
+70e8bfe000-70e8bff000 r--p 00000000 00:00 0 [anon:linker_alloc]
+70e8bff000-70e8c02000 r--s 00000000 fc:00 273 /system/fonts/NotoSansSundanese-Regular.ttf
+70e8c02000-70e8c0f000 r--s 00000000 fc:00 115 /system/fonts/NotoSansAdlam-Regular.ttf
+70e8c0f000-70e8c18000 r-xp 00000000 fc:00 2350 /system/lib64/libnetdutils.so
+70e8c18000-70e8c2e000 ---p 00000000 00:00 0
+70e8c2e000-70e8c2f000 r--p 0000f000 fc:00 2350 /system/lib64/libnetdutils.so
+70e8c2f000-70e8c30000 rw-p 00010000 fc:00 2350 /system/lib64/libnetdutils.so
+70e8c30000-70e8c44000 r--s 00000000 fc:00 283 /system/fonts/NotoSansKannadaUI-Regular.ttf
+70e8c44000-70e8c45000 r-xp 00000000 fc:00 2926 /system/lib64/libhidlallocatorutils.so
+70e8c45000-70e8c63000 ---p 00000000 00:00 0
+70e8c63000-70e8c64000 r--p 0000f000 fc:00 2926 /system/lib64/libhidlallocatorutils.so
+70e8c64000-70e8c65000 rw-p 00010000 fc:00 2926 /system/lib64/libhidlallocatorutils.so
+70e8c65000-70e8c67000 r--s 00000000 fc:00 65 /system/fonts/NotoSansTagalog-Regular.ttf
+70e8c67000-70e8c70000 r--s 00000000 fc:00 294 /system/fonts/NotoSansChakma-Regular.ttf
+70e8c70000-70e8c92000 r--s 00000000 fc:00 116 /system/fonts/NotoSansDevanagari-Regular.ttf
+70e8c92000-70e8c94000 r-xp 00000000 fc:00 2501 /system/lib64/libsync.so
+70e8c94000-70e8cb1000 ---p 00000000 00:00 0
+70e8cb1000-70e8cb2000 r--p 0000f000 fc:00 2501 /system/lib64/libsync.so
+70e8cb2000-70e8cb3000 rw-p 00010000 fc:00 2501 /system/lib64/libsync.so
+70e8cb3000-70e8cc6000 r--s 00000000 fc:00 196 /system/fonts/NotoSerifSinhala-Regular.otf
+70e8cc6000-70e8d5c000 r-xp 00000000 fc:00 2403 /system/lib64/libmedia.so
+70e8d5c000-70e8d70000 ---p 00000000 00:00 0
+70e8d70000-70e8d88000 r--p 00098000 fc:00 2403 /system/lib64/libmedia.so
+70e8d88000-70e8d95000 rw-p 000b0000 fc:00 2403 /system/lib64/libmedia.so
+70e8d95000-70e8d96000 r--p 00000000 00:00 0 [anon:atexit handlers]
+70e8d96000-70e8d99000 r--s 00000000 fc:00 247 /system/fonts/NotoSansSamaritan-Regular.ttf
+70e8d99000-70e8dad000 r--s 00000000 fc:00 108 /system/fonts/NotoSansKannada-Bold.ttf
+70e8dad000-70e8dcd000 r--s 00000000 fc:00 303 /system/fonts/NotoSerifEthiopic-Bold.otf
+70e8dcd000-70e8de5000 r-xp 00000000 fc:00 2954 /system/lib64/libGLESv2.so
+70e8de5000-70e8dfc000 ---p 00000000 00:00 0
+70e8dfc000-70e8dfd000 r--p 0001f000 fc:00 2954 /system/lib64/libGLESv2.so
+70e8dfd000-70e8dfe000 rw-p 00020000 fc:00 2954 /system/lib64/libGLESv2.so
+70e8dfe000-70e8e06000 r--s 00000000 fc:00 265 /system/fonts/NotoSansBalinese-Regular.ttf
+70e8e06000-70e8e0e000 r--s 00000000 fc:00 219 /system/fonts/NotoSansLaoUI-Bold.ttf
+70e8e0e000-70e8e12000 r-xp 00000000 fc:00 2617 /system/lib64/libdebuggerd_client.so
+70e8e12000-70e8e2d000 ---p 00000000 00:00 0
+70e8e2d000-70e8e2e000 r--p 0000f000 fc:00 2617 /system/lib64/libdebuggerd_client.so
+70e8e2e000-70e8e2f000 rw-p 00010000 fc:00 2617 /system/lib64/libdebuggerd_client.so
+70e8e2f000-70e8e4b000 r--s 00000000 fc:00 211 /system/fonts/NotoSerifEthiopic-Regular.otf
+70e8e4b000-70e8e5e000 r-xp 00000000 fc:00 2484 /system/lib64/android.hardware.memtrack@1.0.so
+70e8e5e000-70e8e78000 ---p 00000000 00:00 0
+70e8e78000-70e8e7a000 r--p 0001e000 fc:00 2484 /system/lib64/android.hardware.memtrack@1.0.so
+70e8e7a000-70e8e7b000 rw-p 00020000 fc:00 2484 /system/lib64/android.hardware.memtrack@1.0.so
+70e8e7b000-70e8e7d000 r--s 00000000 fc:00 261 /system/fonts/NotoSansShavian-Regular.ttf
+70e8e7d000-70e8e80000 r--s 00000000 fc:00 204 /system/fonts/NotoSansRunic-Regular.ttf
+70e8e80000-70e8ea1000 r-xp 00000000 fc:00 2512 /system/lib64/android.hardware.configstore@1.0.so
+70e8ea1000-70e8ebb000 ---p 00000000 00:00 0
+70e8ebb000-70e8ebe000 r--p 0002d000 fc:00 2512 /system/lib64/android.hardware.configstore@1.0.so
+70e8ebe000-70e8ebf000 rw-p 00030000 fc:00 2512 /system/lib64/android.hardware.configstore@1.0.so
+70e8ebf000-70e8ee3000 r--s 00000000 fc:00 226 /system/fonts/NotoSansEthiopic-Bold.ttf
+70e8ee3000-70e8f1a000 r-xp 00000000 fc:00 2337 /system/lib64/libm.so
+70e8f1a000-70e8f32000 ---p 00000000 00:00 0
+70e8f32000-70e8f33000 r--p 0003f000 fc:00 2337 /system/lib64/libm.so
+70e8f33000-70e8f34000 rw-p 00040000 fc:00 2337 /system/lib64/libm.so
+70e8f34000-70e8f36000 r--s 00000000 fc:00 133 /system/fonts/NotoSansRejang-Regular.ttf
+70e8f36000-70e8f38000 r--s 00000000 fc:00 69 /system/fonts/NotoSansPhoenician-Regular.ttf
+70e8f38000-70e8f40000 r--s 00000000 fc:00 245 /system/fonts/NotoSansLaoUI-Regular.ttf
+70e8f40000-70e8f45000 r-xp 00000000 fc:00 2341 /system/lib64/libstagefright_codecbase.so
+70e8f45000-70e8f5f000 ---p 00000000 00:00 0
+70e8f5f000-70e8f60000 r--p 0000f000 fc:00 2341 /system/lib64/libstagefright_codecbase.so
+70e8f60000-70e8f61000 rw-p 00010000 fc:00 2341 /system/lib64/libstagefright_codecbase.so
+70e8f61000-70e8f62000 r--p 00000000 00:00 0 [anon:atexit handlers]
+70e8f62000-70e8f66000 r--s 00000000 fc:00 225 /system/fonts/NotoSansOldPersian-Regular.ttf
+70e8f66000-70e8f89000 r--s 00000000 fc:00 167 /system/fonts/NotoSansEthiopic-Regular.ttf
+70e8f89000-70e8f92000 r-xp 00000000 fc:00 2515 /system/lib64/libGLESv1_CM.so
+70e8f92000-70e8fa8000 ---p 00000000 00:00 0
+70e8fa8000-70e8fa9000 r--p 0000f000 fc:00 2515 /system/lib64/libGLESv1_CM.so
+70e8fa9000-70e8faa000 rw-p 00010000 fc:00 2515 /system/lib64/libGLESv1_CM.so
+70e8faa000-70e8fad000 r--s 00000000 fc:00 206 /system/fonts/NotoSansOsage-Regular.ttf
+70e8fad000-70e8fb5000 r--s 00000000 fc:00 121 /system/fonts/NotoSerifLao-Bold.ttf
+70e8fb5000-70e8fd3000 r--s 00000000 fc:00 68 /system/fonts/NotoNaskhArabicUI-Bold.ttf
+70e8fd3000-70e9010000 r-xp 00000000 fc:00 2600 /system/lib64/android.hardware.cas@1.0.so
+70e9010000-70e9026000 ---p 00000000 00:00 0
+70e9026000-70e902c000 r--p 0004a000 fc:00 2600 /system/lib64/android.hardware.cas@1.0.so
+70e902c000-70e902d000 rw-p 00050000 fc:00 2600 /system/lib64/android.hardware.cas@1.0.so
+70e902d000-70e902e000 r--s 00000000 00:05 31475 /dev/ashmem/5c7d41a6-003d-45a5-9e3b-2d34c5829a2d (deleted)
+70e902e000-70e9043000 r--s 00000000 fc:00 120 /system/fonts/NotoSansKannada-Regular.ttf
+70e9043000-70e9067000 r-xp 00000000 fc:00 2729 /system/lib64/libexpat.so
+70e9067000-70e9081000 ---p 00000000 00:00 0
+70e9081000-70e9083000 r--p 0002e000 fc:00 2729 /system/lib64/libexpat.so
+70e9083000-70e9084000 rw-p 00030000 fc:00 2729 /system/lib64/libexpat.so
+70e9084000-70e9086000 r--s 00000000 fc:00 155 /system/fonts/NotoSansOsmanya-Regular.ttf
+70e9086000-70e90c3000 r--s 00000000 fc:00 91 /system/fonts/NotoSerif-Regular.ttf
+70e90c3000-70e91ce000 r-xp 00000000 fc:00 2647 /system/lib64/libcrypto.so
+70e91ce000-70e91e2000 ---p 00000000 00:00 0
+70e91e2000-70e91f3000 r--p 0010f000 fc:00 2647 /system/lib64/libcrypto.so
+70e91f3000-70e91f4000 rw-p 00120000 fc:00 2647 /system/lib64/libcrypto.so
+70e91f4000-70e91f5000 rw-p 00000000 00:00 0 [anon:.bss]
+70e91f5000-70e91fa000 r--s 00000000 fc:00 149 /system/fonts/NotoSansNKo-Regular.ttf
+70e91fa000-70e9202000 r--s 00000000 fc:00 198 /system/fonts/NotoSerifLao-Regular.ttf
+70e9202000-70e921b000 r-xp 00000000 fc:00 2682 /system/lib64/libmedia_helper.so
+70e921b000-70e922d000 ---p 00000000 00:00 0
+70e922d000-70e9230000 r--p 0001d000 fc:00 2682 /system/lib64/libmedia_helper.so
+70e9230000-70e9231000 rw-p 00020000 fc:00 2682 /system/lib64/libmedia_helper.so
+70e9231000-70e924a000 r--s 00000000 fc:00 232 /system/fonts/NotoSansBengali-Bold.ttf
+70e924a000-70e9256000 r-xp 00000000 fc:00 2467 /system/lib64/libsoundtrigger.so
+70e9256000-70e9272000 ---p 00000000 00:00 0
+70e9272000-70e9276000 r--p 0000c000 fc:00 2467 /system/lib64/libsoundtrigger.so
+70e9276000-70e9277000 rw-p 00010000 fc:00 2467 /system/lib64/libsoundtrigger.so
+70e9277000-70e9278000 r--s 00000000 fc:01 1177 /vendor/overlay/Pixel/PixelThemeOverlay.apk
+70e9278000-70e927c000 r--s 00000000 fc:00 215 /system/fonts/NotoSansNewTaiLue-Regular.ttf
+70e927c000-70e929a000 r--s 00000000 fc:00 235 /system/fonts/NotoNaskhArabicUI-Regular.ttf
+70e929a000-70e929b000 r-xp 00000000 fc:00 2375 /system/lib64/android.hardware.graphics.common@1.1.so
+70e929b000-70e92b9000 ---p 00000000 00:00 0
+70e92b9000-70e92ba000 r--p 0000f000 fc:00 2375 /system/lib64/android.hardware.graphics.common@1.1.so
+70e92ba000-70e92bb000 rw-p 00010000 fc:00 2375 /system/lib64/android.hardware.graphics.common@1.1.so
+70e92bb000-70e92da000 r--s 00000000 fc:00 281 /system/fonts/GoogleSans-BoldItalic.ttf
+70e92da000-70e9302000 r-xp 00000000 fc:00 2529 /system/lib64/libinput.so
+70e9302000-70e931b000 ---p 00000000 00:00 0
+70e931b000-70e9322000 r--p 00029000 fc:00 2529 /system/lib64/libinput.so
+70e9322000-70e9323000 rw-p 00030000 fc:00 2529 /system/lib64/libinput.so
+70e9323000-70e9340000 r--s 00000000 fc:00 130 /system/fonts/NotoNaskhArabic-Bold.ttf
+70e9340000-70e934b000 r-xp 00000000 fc:00 2451 /system/lib64/libbpf.so
+70e934b000-70e935f000 ---p 00000000 00:00 0
+70e935f000-70e9360000 r--p 0000f000 fc:00 2451 /system/lib64/libbpf.so
+70e9360000-70e9361000 rw-p 00010000 fc:00 2451 /system/lib64/libbpf.so
+70e9361000-70e9367000 r--s 00000000 fc:00 96 /system/fonts/NotoSansKharoshthi-Regular.ttf
+70e9367000-70e9385000 r--s 00000000 fc:00 151 /system/fonts/GoogleSans-Bold.ttf
+70e9385000-70e93b8000 r-xp 00000000 fc:00 2494 /system/lib64/libpng.so
+70e93b8000-70e93d4000 ---p 00000000 00:00 0
+70e93d4000-70e93d5000 r--p 0003f000 fc:00 2494 /system/lib64/libpng.so
+70e93d5000-70e93d6000 rw-p 00040000 fc:00 2494 /system/lib64/libpng.so
+70e93d6000-70e93d7000 r--s 00004000 fc:01 1177 /vendor/overlay/Pixel/PixelThemeOverlay.apk
+70e93d7000-70e93d9000 r--s 00000000 fc:00 295 /system/fonts/NotoSansOldTurkic-Regular.ttf
+70e93d9000-70e93e5000 r--s 00000000 fc:00 86 /system/fonts/NotoSerifKhmer-Bold.otf
+70e93e5000-70e9404000 r--s 00000000 fc:00 240 /system/fonts/GoogleSans-MediumItalic.ttf
+70e9404000-70e9409000 r-xp 00000000 fc:00 2404 /system/lib64/libhidlmemory.so
+70e9409000-70e9423000 ---p 00000000 00:00 0
+70e9423000-70e9424000 r--p 0000f000 fc:00 2404 /system/lib64/libhidlmemory.so
+70e9424000-70e9425000 rw-p 00010000 fc:00 2404 /system/lib64/libhidlmemory.so
+70e9425000-70e943e000 r--s 00000000 fc:00 185 /system/fonts/NotoSansBengali-Regular.ttf
+70e943e000-70e945c000 r--s 00000000 fc:00 129 /system/fonts/GoogleSans-Medium.ttf
+70e945c000-70e960c000 r-xp 00000000 fc:00 2398 /system/lib64/libstagefright.so
+70e960c000-70e9625000 ---p 00000000 00:00 0
+70e9625000-70e9638000 r--p 001bd000 fc:00 2398 /system/lib64/libstagefright.so
+70e9638000-70e966c000 rw-p 001d0000 fc:00 2398 /system/lib64/libstagefright.so
+70e966c000-70e966d000 rw-p 00000000 00:00 0 [anon:.bss]
+70e966d000-70e966e000 r--s 00000000 103:1d 1474566 /data/resource-cache/vendor@overlay@Pixel@PixelThemeOverlay.apk@idmap
+70e966e000-70e9672000 r--s 00000000 fc:00 241 /system/fonts/NotoSansMeeteiMayek-Regular.ttf
+70e9672000-70e9680000 r--s 00000000 fc:00 150 /system/fonts/NotoSansMalayalamUI-Bold.ttf
+70e9680000-70e96a7000 r-xp 00000000 fc:00 2365 /system/lib64/libhwbinder.so
+70e96a7000-70e96bd000 ---p 00000000 00:00 0
+70e96bd000-70e96bf000 r--p 0002e000 fc:00 2365 /system/lib64/libhwbinder.so
+70e96bf000-70e96c0000 rw-p 00030000 fc:00 2365 /system/lib64/libhwbinder.so
+70e96c0000-70e96c1000 r--s 00088000 103:1d 1736830 /data/app/com.google.sample.tunnel-HGGRU03Gu1Mwkf_-RnFmvw==/base.apk
+70e96c1000-70e96cb000 r--s 00000000 fc:00 94 /system/fonts/NotoSansKhmerUI-Regular.ttf
+70e96cb000-70e96d9000 r--s 00000000 fc:00 275 /system/fonts/NotoSansMalayalamUI-Regular.ttf
+70e96d9000-70e96dd000 r-xp 00000000 fc:00 2386 /system/lib64/libusbhost.so
+70e96dd000-70e96f8000 ---p 00000000 00:00 0
+70e96f8000-70e96f9000 r--p 0000f000 fc:00 2386 /system/lib64/libusbhost.so
+70e96f9000-70e96fa000 rw-p 00010000 fc:00 2386 /system/lib64/libusbhost.so
+70e96fa000-70e96fb000 r--p 00000000 00:05 10266154 /dev/ashmem/dalvik-classes.dex extracted in memory from /data/app/com.google.sample.tunnel-HGGRU03Gu1Mwkf_-RnFmvw==/base.apk (deleted)
+70e96fb000-70e9701000 r--s 00000000 fc:00 280 /system/fonts/NotoSansCoptic-Regular.ttf
+70e9701000-70e9720000 r-xp 00000000 fc:00 2490 /system/lib64/libstagefright_bufferqueue_helper.so
+70e9720000-70e973b000 ---p 00000000 00:00 0
+70e973b000-70e973e000 r--p 0002d000 fc:00 2490 /system/lib64/libstagefright_bufferqueue_helper.so
+70e973e000-70e9740000 rw-p 00030000 fc:00 2490 /system/lib64/libstagefright_bufferqueue_helper.so
+70e9740000-70e9742000 r--s 00000000 fc:00 141 /system/fonts/NotoSansOldSouthArabian-Regular.ttf
+70e9742000-70e974c000 r--s 00000000 fc:00 229 /system/fonts/NotoSerifKhmer-Regular.otf
+70e974c000-70e9759000 r--s 00000000 fc:00 260 /system/fonts/NotoSerifMalayalam-Bold.ttf
+70e9759000-70e97c7000 r-xp 00000000 fc:00 2428 /system/lib64/libstagefright_omx.so
+70e97c7000-70e97dc000 ---p 00000000 00:00 0
+70e97dc000-70e97e6000 r--p 00076000 fc:00 2428 /system/lib64/libstagefright_omx.so
+70e97e6000-70e97ed000 rw-p 00080000 fc:00 2428 /system/lib64/libstagefright_omx.so
+70e97ed000-70e97fa000 r--s 00000000 fc:00 66 /system/fonts/NotoSerifMalayalam-Regular.ttf
+70e97fa000-70e9819000 r--s 00000000 fc:00 183 /system/fonts/GoogleSans-Italic.ttf
+70e9819000-70e9856000 r-xp 00000000 fc:00 2434 /system/lib64/libprotobuf-cpp-lite.so
+70e9856000-70e9867000 ---p 00000000 00:00 0
+70e9867000-70e9869000 r--p 0003e000 fc:00 2434 /system/lib64/libprotobuf-cpp-lite.so
+70e9869000-70e986a000 rw-p 00040000 fc:00 2434 /system/lib64/libprotobuf-cpp-lite.so
+70e986a000-70e9873000 r--s 00000000 fc:00 134 /system/fonts/NotoSansKhmerUI-Bold.ttf
+70e9873000-70e9891000 r--s 00000000 fc:00 81 /system/fonts/GoogleSans-Regular.ttf
+70e9891000-70e989e000 r-xp 00000000 fc:00 2377 /system/lib64/libmediametrics.so
+70e989e000-70e98ae000 ---p 00000000 00:00 0
+70e98ae000-70e98b0000 r--p 0000e000 fc:00 2377 /system/lib64/libmediametrics.so
+70e98b0000-70e98b1000 rw-p 00010000 fc:00 2377 /system/lib64/libmediametrics.so
+70e98b1000-70e98b9000 r--s 00000000 fc:00 152 /system/fonts/NotoSansLao-Bold.ttf
+70e98b9000-70e98c7000 r--s 00000000 fc:00 279 /system/fonts/NotoSansMalayalam-Bold.ttf
+70e98c7000-70e98ca000 r-xp 00000000 fc:00 2952 /system/lib64/libETC1.so
+70e98ca000-70e98e6000 ---p 00000000 00:00 0
+70e98e6000-70e98e7000 r--p 0000f000 fc:00 2952 /system/lib64/libETC1.so
+70e98e7000-70e98e8000 rw-p 00010000 fc:00 2952 /system/lib64/libETC1.so
+70e98e8000-70e98e9000 r--s 00000000 fc:00 1121 /system/usr/hyphen-data/hyph-und-ethi.hyb
+70e98e9000-70e98ef000 r--s 00000000 fc:00 64 /system/fonts/NotoSansBrahmi-Regular.ttf
+70e98ef000-70e990f000 rw-p 00000000 00:05 10271012 /dev/ashmem/dalvik-CompilerMetadata (deleted)
+70e990f000-70e9926000 r-xp 00000000 fc:00 2526 /system/lib64/libbacktrace.so
+70e9926000-70e993e000 ---p 00000000 00:00 0
+70e993e000-70e993f000 r--p 0001f000 fc:00 2526 /system/lib64/libbacktrace.so
+70e993f000-70e9940000 rw-p 00020000 fc:00 2526 /system/lib64/libbacktrace.so
+70e9940000-70e9941000 r--s 00000000 fc:00 1129 /system/usr/hyphen-data/hyph-tk.hyb
+70e9941000-70e99a4000 r-xp 00000000 fc:00 2528 /system/lib64/libcamera_client.so
+70e99a4000-70e99bc000 ---p 00000000 00:00 0
+70e99bc000-70e99c9000 r--p 00063000 fc:00 2528 /system/lib64/libcamera_client.so
+70e99c9000-70e99d0000 rw-p 00070000 fc:00 2528 /system/lib64/libcamera_client.so
+70e99d0000-70e99d1000 r--p 00000000 00:00 0 [anon:linker_alloc]
+70e99d1000-70e99d3000 r--s 00000000 fc:00 200 /system/fonts/NotoSansOldItalic-Regular.ttf
+70e99d3000-70e99e1000 r--s 00000000 fc:00 153 /system/fonts/NotoSansMalayalam-Regular.ttf
+70e99e1000-70e9a01000 rw-p 00000000 00:05 10271011 /dev/ashmem/dalvik-CompilerMetadata (deleted)
+70e9a01000-70e9a1e000 r-xp 00000000 fc:00 2542 /system/lib64/libimg_utils.so
+70e9a1e000-70e9a39000 ---p 00000000 00:00 0
+70e9a39000-70e9a3c000 r--p 0001d000 fc:00 2542 /system/lib64/libimg_utils.so
+70e9a3c000-70e9a3f000 rw-p 00020000 fc:00 2542 /system/lib64/libimg_utils.so
+70e9a3f000-70e9a5c000 r--s 00000000 fc:00 262 /system/fonts/NotoNaskhArabic-Regular.ttf
+70e9a5c000-70e9a69000 r-xp 00000000 fc:00 2706 /system/lib64/libziparchive.so
+70e9a69000-70e9a7b000 ---p 00000000 00:00 0
+70e9a7b000-70e9a7c000 r--p 0000f000 fc:00 2706 /system/lib64/libziparchive.so
+70e9a7c000-70e9a7d000 rw-p 00010000 fc:00 2706 /system/lib64/libziparchive.so
+70e9a7d000-70e9a85000 r--s 00000000 fc:00 119 /system/fonts/NotoSansLao-Regular.ttf
+70e9a85000-70e9a8e000 r--s 00000000 fc:00 77 /system/fonts/NotoSansTamilUI-Bold.ttf
+70e9a8e000-70e9a97000 r--s 00000000 fc:00 160 /system/fonts/NotoSansTamilUI-Regular.ttf
+70e9a97000-70e9a9d000 r-xp 00000000 fc:00 2536 /system/lib64/libnativehelper.so
+70e9a9d000-70e9ab6000 ---p 00000000 00:00 0
+70e9ab6000-70e9ab7000 r--p 0000f000 fc:00 2536 /system/lib64/libnativehelper.so
+70e9ab7000-70e9ab8000 rw-p 00010000 fc:00 2536 /system/lib64/libnativehelper.so
+70e9ab8000-70e9ab9000 r--s 00000000 fc:00 1134 /system/usr/hyphen-data/hyph-te.hyb
+70e9ab9000-70e9ac2000 r--s 00000000 fc:00 246 /system/fonts/NotoSerifTamil-Bold.ttf
+70e9ac2000-70e9acb000 r--s 00000000 fc:00 302 /system/fonts/NotoSerifTamil-Regular.ttf
+70e9acb000-70e9af4000 r-xp 00000000 fc:00 2950 /system/lib64/libmemunreachable.so
+70e9af4000-70e9b09000 ---p 00000000 00:00 0
+70e9b09000-70e9b0b000 r--p 0002e000 fc:00 2950 /system/lib64/libmemunreachable.so
+70e9b0b000-70e9b0c000 rw-p 00030000 fc:00 2950 /system/lib64/libmemunreachable.so
+70e9b0c000-70e9b0d000 r--s 00000000 fc:00 1088 /system/usr/hyphen-data/hyph-ta.hyb
+70e9b0d000-70e9b0f000 r--s 00000000 fc:00 72 /system/fonts/NotoSansOlChiki-Regular.ttf
+70e9b0f000-70e9b2f000 rw-p 00000000 00:05 10271010 /dev/ashmem/dalvik-CompilerMetadata (deleted)
+70e9b2f000-70e9b4f000 r--s 00000000 00:10 16633 /dev/__properties__/u:object_r:persist_debug_prop:s0
+70e9b4f000-70e9b65000 r-xp 00000000 fc:00 2920 /system/lib64/android.hardware.cas.native@1.0.so
+70e9b65000-70e9b7b000 ---p 00000000 00:00 0
+70e9b7b000-70e9b7d000 r--p 0001e000 fc:00 2920 /system/lib64/android.hardware.cas.native@1.0.so
+70e9b7d000-70e9b7e000 rw-p 00020000 fc:00 2920 /system/lib64/android.hardware.cas.native@1.0.so
+70e9b7e000-70e9b7f000 r--s 00000000 fc:00 1145 /system/usr/hyphen-data/hyph-pt.hyb
+70e9b7f000-70e9b83000 r--s 00000000 fc:00 277 /system/fonts/NotoSansMandaic-Regular.ttf
+70e9b83000-70e9bdb000 r-xp 00000000 fc:00 2334 /system/lib64/libsonivox.so
+70e9bdb000-70e9bf2000 ---p 00000000 00:00 0
+70e9bf2000-70e9bf3000 r--p 0005f000 fc:00 2334 /system/lib64/libsonivox.so
+70e9bf3000-70e9bf4000 rw-p 00060000 fc:00 2334 /system/lib64/libsonivox.so
+70e9bf4000-70e9bfb000 rw-p 00000000 00:00 0 [anon:.bss]
+70e9bfb000-70e9c01000 r--s 00000000 fc:00 123 /system/fonts/NotoSansCham-Bold.ttf
+70e9c01000-70e9c0a000 r--s 00000000 fc:00 255 /system/fonts/NotoSansTamil-Bold.ttf
+70e9c0a000-70e9c13000 r--s 00000000 fc:00 135 /system/fonts/NotoSansTamil-Regular.ttf
+70e9c13000-70e9c15000 r-xp 00000000 fc:00 2519 /system/lib64/libgraphicsenv.so
+70e9c15000-70e9c32000 ---p 00000000 00:00 0
+70e9c32000-70e9c33000 r--p 0000f000 fc:00 2519 /system/lib64/libgraphicsenv.so
+70e9c33000-70e9c34000 rw-p 00010000 fc:00 2519 /system/lib64/libgraphicsenv.so
+70e9c34000-70e9c3a000 r--s 00000000 fc:00 259 /system/fonts/NotoSansCham-Regular.ttf
+70e9c3a000-70e9c42000 r--s 00000000 fc:00 114 /system/fonts/NotoSansGurmukhiUI-Bold.ttf
+70e9c42000-70e9c4a000 r--s 00000000 fc:00 122 /system/fonts/NotoSansGurmukhiUI-Regular.ttf
+70e9c4a000-70e9c5f000 r-xp 00000000 fc:00 2348 /system/lib64/android.hidl.allocator@1.0.so
+70e9c5f000-70e9c77000 ---p 00000000 00:00 0
+70e9c77000-70e9c79000 r--p 0001e000 fc:00 2348 /system/lib64/android.hidl.allocator@1.0.so
+70e9c79000-70e9c7a000 rw-p 00020000 fc:00 2348 /system/lib64/android.hidl.allocator@1.0.so
+70e9c7a000-70e9c7b000 r--s 00000000 fc:00 1095 /system/usr/hyphen-data/hyph-pa.hyb
+70e9c7b000-70e9c83000 r--s 00000000 fc:00 298 /system/fonts/NotoSerifGurmukhi-Bold.otf
+70e9c83000-70e9d01000 r-xp 00000000 fc:00 2665 /system/lib64/libbinder.so
+70e9d01000-70e9d1e000 ---p 00000000 00:00 0
+70e9d1e000-70e9d2e000 r--p 00080000 fc:00 2665 /system/lib64/libbinder.so
+70e9d2e000-70e9d2f000 rw-p 00090000 fc:00 2665 /system/lib64/libbinder.so
+70e9d2f000-70e9d4f000 rw-p 00000000 00:05 10271009 /dev/ashmem/dalvik-CompilerMetadata (deleted)
+70e9d4f000-70e9d53000 r-xp 00000000 fc:00 2454 /system/lib64/libaudiomanager.so
+70e9d53000-70e9d6e000 ---p 00000000 00:00 0
+70e9d6e000-70e9d6f000 r--p 0000f000 fc:00 2454 /system/lib64/libaudiomanager.so
+70e9d6f000-70e9d70000 rw-p 00010000 fc:00 2454 /system/lib64/libaudiomanager.so
+70e9d70000-70e9d71000 r--s 00000000 fc:00 1087 /system/usr/hyphen-data/hyph-or.hyb
+70e9d71000-70e9d91000 rw-p 00000000 00:05 10271008 /dev/ashmem/dalvik-CompilerMetadata (deleted)
+70e9d91000-70e9e21000 r-xp 00000000 fc:00 2627 /system/lib64/libft2.so
+70e9e21000-70e9e37000 ---p 00000000 00:00 0
+70e9e37000-70e9e3c000 r--p 0009b000 fc:00 2627 /system/lib64/libft2.so
+70e9e3c000-70e9e3d000 rw-p 000a0000 fc:00 2627 /system/lib64/libft2.so
+70e9e3d000-70e9e3e000 r--s 00000000 fc:00 1142 /system/usr/hyphen-data/hyph-mr.hyb
+70e9e3e000-70e9e45000 r--s 00000000 fc:00 88 /system/fonts/NotoSerifGurmukhi-Regular.otf
+70e9e45000-70e9e65000 r--s 00000000 00:10 16594 /dev/__properties__/u:object_r:exported3_default_prop:s0
+70e9e65000-70e9e7f000 r-xp 00000000 fc:00 2643 /system/lib64/libunwind.so
+70e9e7f000-70e9e94000 ---p 00000000 00:00 0
+70e9e94000-70e9e95000 r--p 0001f000 fc:00 2643 /system/lib64/libunwind.so
+70e9e95000-70e9e96000 rw-p 00020000 fc:00 2643 /system/lib64/libunwind.so
+70e9e96000-70e9eff000 rw-p 00000000 00:00 0 [anon:.bss]
+70e9eff000-70e9f00000 r--s 00000000 fc:00 1130 /system/usr/hyphen-data/hyph-ml.hyb
+70e9f00000-70e9f02000 r--s 00000000 fc:00 75 /system/fonts/NotoSansOgham-Regular.ttf
+70e9f02000-70e9f0a000 r--s 00000000 fc:00 193 /system/fonts/NotoSansGurmukhi-Bold.ttf
+70e9f0a000-70ea022000 r-xp 00000000 fc:00 2328 /system/lib64/libsqlite.so
+70ea022000-70ea033000 ---p 00000000 00:00 0
+70ea033000-70ea036000 r--p 0011d000 fc:00 2328 /system/lib64/libsqlite.so
+70ea036000-70ea038000 rw-p 00120000 fc:00 2328 /system/lib64/libsqlite.so
+70ea038000-70ea03c000 r--s 00000000 fc:00 285 /system/fonts/NotoSansGlagolitic-Regular.ttf
+70ea03c000-70ea04c000 r--s 00000000 fc:00 184 /system/fonts/NotoSerifGujarati-Bold.ttf
+70ea04c000-70ea060000 r-xp 00000000 fc:00 2731 /system/lib64/libstatslog.so
+70ea060000-70ea07b000 ---p 00000000 00:00 0
+70ea07b000-70ea07c000 r--p 0001f000 fc:00 2731 /system/lib64/libstatslog.so
+70ea07c000-70ea07d000 rw-p 00020000 fc:00 2731 /system/lib64/libstatslog.so
+70ea07d000-70ea081000 r--s 00000000 fc:00 182 /system/fonts/NotoSansBatak-Regular.ttf
+70ea081000-70ea091000 r--s 00000000 fc:00 264 /system/fonts/NotoSerifGujarati-Regular.ttf
+70ea091000-70ea160000 r-xp 00000000 fc:00 2728 /system/lib64/libdng_sdk.so
+70ea160000-70ea173000 ---p 00000000 00:00 0
+70ea173000-70ea17a000 r--p 000d9000 fc:00 2728 /system/lib64/libdng_sdk.so
+70ea17a000-70ea17b000 rw-p 000e0000 fc:00 2728 /system/lib64/libdng_sdk.so
+70ea17b000-70ea198000 r--s 00000000 fc:00 223 /system/fonts/DancingScript-Bold.ttf
+70ea198000-70ea19c000 r-xp 00000000 fc:00 2344 /system/lib64/libnativewindow.so
+70ea19c000-70ea1b7000 ---p 00000000 00:00 0
+70ea1b7000-70ea1b8000 r--p 0000f000 fc:00 2344 /system/lib64/libnativewindow.so
+70ea1b8000-70ea1b9000 rw-p 00010000 fc:00 2344 /system/lib64/libnativewindow.so
+70ea1b9000-70ea1bd000 r--s 00000000 fc:00 98 /system/fonts/NotoSansAhom-Regular.otf
+70ea1bd000-70ea1d1000 r--s 00000000 fc:00 104 /system/fonts/NotoSerifDevanagari-Bold.ttf
+70ea1d1000-70ea1d4000 r-xp 00000000 fc:00 2923 /system/lib64/libstdc++.so
+70ea1d4000-70ea1f0000 ---p 00000000 00:00 0
+70ea1f0000-70ea1f1000 r--p 0000f000 fc:00 2923 /system/lib64/libstdc++.so
+70ea1f1000-70ea1f2000 rw-p 00010000 fc:00 2923 /system/lib64/libstdc++.so
+70ea1f2000-70ea1f4000 r--s 00000000 fc:00 117 /system/fonts/NotoSansLydian-Regular.ttf
+70ea1f4000-70ea211000 r--s 00000000 fc:00 239 /system/fonts/DancingScript-Regular.ttf
+70ea211000-70ea24a000 r-xp 00000000 fc:00 2933 /system/lib64/android.hardware.graphics.bufferqueue@1.0.so
+70ea24a000-70ea268000 ---p 00000000 00:00 0
+70ea268000-70ea26c000 r--p 0003c000 fc:00 2933 /system/lib64/android.hardware.graphics.bufferqueue@1.0.so
+70ea26c000-70ea26d000 rw-p 00040000 fc:00 2933 /system/lib64/android.hardware.graphics.bufferqueue@1.0.so
+70ea26d000-70ea26f000 r--s 00000000 fc:00 244 /system/fonts/NotoSansLycian-Regular.ttf
+70ea26f000-70ea273000 r--s 00000000 fc:00 173 /system/fonts/NotoSansThaana-Bold.ttf
+70ea273000-70ea287000 r--s 00000000 fc:00 106 /system/fonts/NotoSerifDevanagari-Regular.ttf
+70ea287000-70ea29e000 r-xp 00000000 fc:00 2938 /system/lib64/libpiex.so
+70ea29e000-70ea2b6000 ---p 00000000 00:00 0
+70ea2b6000-70ea2b7000 r--p 0001f000 fc:00 2938 /system/lib64/libpiex.so
+70ea2b7000-70ea2b8000 rw-p 00020000 fc:00 2938 /system/lib64/libpiex.so
+70ea2b8000-70ea2c0000 r--s 00000000 fc:00 113 /system/fonts/NotoSansGurmukhi-Regular.ttf
+70ea2c0000-70ea2c6000 r--s 00000000 fc:00 263 /system/fonts/NotoSerifGeorgian-Bold.ttf
+70ea2c6000-70ea2cc000 r--s 00000000 fc:00 249 /system/fonts/NotoSerifGeorgian-Regular.ttf
+70ea2cc000-70ea9b4000 r-xp 00000000 fc:00 2532 /system/lib64/libhwui.so
+70ea9b4000-70ea9d3000 ---p 00000000 00:00 0
+70ea9d3000-70eaa0b000 r--p 006e8000 fc:00 2532 /system/lib64/libhwui.so
+70eaa0b000-70eaa0c000 rw-p 00720000 fc:00 2532 /system/lib64/libhwui.so
+70eaa0c000-70eaa11000 rw-p 00000000 00:00 0 [anon:.bss]
+70eaa11000-70eaa12000 r--s 00000000 fc:00 1110 /system/usr/hyphen-data/hyph-la.hyb
+70eaa12000-70eaa16000 r--s 00000000 fc:00 87 /system/fonts/NotoSansThaana-Regular.ttf
+70eaa16000-70eaa1b000 r--s 00000000 fc:00 218 /system/fonts/NotoSansGeorgian-Bold.ttf
+70eaa1b000-70eaa20000 r--s 00000000 fc:00 125 /system/fonts/NotoSansGeorgian-Regular.ttf
+70eaa20000-70eaa40000 rw-p 00000000 00:05 10271007 /dev/ashmem/dalvik-CompilerMetadata (deleted)
+70eaa40000-70eaaa0000 r-xp 00000000 fc:00 2384 /system/lib64/libhidltransport.so
+70eaaa0000-70eaabe000 ---p 00000000 00:00 0
+70eaabe000-70eaac6000 r--p 00068000 fc:00 2384 /system/lib64/libhidltransport.so
+70eaac6000-70eaac7000 rw-p 00070000 fc:00 2384 /system/lib64/libhidltransport.so
+70eaac7000-70eaacb000 r--s 00000000 fc:00 192 /system/fonts/NotoSerifArmenian-Bold.ttf
+70eaacb000-70eaad0000 r--s 00000000 fc:00 210 /system/fonts/NotoSansThaiUI-Bold.ttf
+70eaad0000-70eaaf0000 rw-p 00000000 00:05 10271006 /dev/ashmem/dalvik-CompilerMetadata (deleted)
+70eaaf0000-70eab10000 rw-p 00000000 00:05 10271005 /dev/ashmem/dalvik-CompilerMetadata (deleted)
+70eab10000-70eab57000 r-xp 00000000 fc:00 2546 /system/lib64/libmedia_omx.so
+70eab57000-70eab6d000 ---p 00000000 00:00 0
+70eab6d000-70eab7a000 r--p 00053000 fc:00 2546 /system/lib64/libmedia_omx.so
+70eab7a000-70eab7f000 rw-p 00060000 fc:00 2546 /system/lib64/libmedia_omx.so
+70eab7f000-70eab80000 r--s 00000000 fc:00 1119 /system/usr/hyphen-data/hyph-kn.hyb
+70eab80000-70eab86000 r--s 00000000 fc:00 224 /system/fonts/NotoSansThaiUI-Regular.ttf
+70eab86000-70eab8b000 r--s 00000000 fc:00 300 /system/fonts/NotoSerifThai-Bold.ttf
+70eab8b000-70eabab000 rw-p 00000000 00:05 10271004 /dev/ashmem/dalvik-CompilerMetadata (deleted)
+70eabab000-70eac21000 r-xp 00000000 fc:00 2385 /system/lib64/libvintf.so
+70eac21000-70eac31000 ---p 00000000 00:00 0
+70eac31000-70eac36000 r--p 0007b000 fc:00 2385 /system/lib64/libvintf.so
+70eac36000-70eac37000 rw-p 00080000 fc:00 2385 /system/lib64/libvintf.so
+70eac37000-70eac39000 rw-p 00000000 00:00 0 [anon:.bss]
+70eac39000-70eac3a000 r--s 00000000 fc:00 1104 /system/usr/hyphen-data/hyph-hy.hyb
+70eac3a000-70eac3f000 r--s 00000000 fc:00 212 /system/fonts/NotoSerifThai-Regular.ttf
+70eac3f000-70eac44000 r--s 00000000 fc:00 220 /system/fonts/NotoSansThai-Bold.ttf
+70eac44000-70eacb2000 r-xp 00000000 fc:00 2606 /system/lib64/android.hardware.media.omx@1.0.so
+70eacb2000-70eaccf000 ---p 00000000 00:00 0
+70eaccf000-70eacd8000 r--p 00077000 fc:00 2606 /system/lib64/android.hardware.media.omx@1.0.so
+70eacd8000-70eacd9000 rw-p 00080000 fc:00 2606 /system/lib64/android.hardware.media.omx@1.0.so
+70eacd9000-70eacdf000 r--s 00000000 fc:00 169 /system/fonts/NotoSansThai-Regular.ttf
+70eacdf000-70eace9000 r--s 00000000 fc:00 140 /system/fonts/CarroisGothicSC-Regular.ttf
+70eace9000-70ead09000 rw-p 00000000 00:05 10271003 /dev/ashmem/dalvik-CompilerMetadata (deleted)
+70ead09000-70ead22000 r-xp 00000000 fc:00 2539 /system/lib64/android.hardware.graphics.mapper@2.1.so
+70ead22000-70ead34000 ---p 00000000 00:00 0
+70ead34000-70ead37000 r--p 0001d000 fc:00 2539 /system/lib64/android.hardware.graphics.mapper@2.1.so
+70ead37000-70ead38000 rw-p 00020000 fc:00 2539 /system/lib64/android.hardware.graphics.mapper@2.1.so
+70ead38000-70ead47000 r--s 00000000 fc:00 188 /system/fonts/ComingSoon.ttf
+70ead47000-70ead5d000 r-xp 00000000 fc:00 2379 /system/lib64/libselinux.so
+70ead5d000-70ead76000 ---p 00000000 00:00 0
+70ead76000-70ead77000 r--p 0001f000 fc:00 2379 /system/lib64/libselinux.so
+70ead77000-70ead78000 rw-p 00020000 fc:00 2379 /system/lib64/libselinux.so
+70ead78000-70ead79000 rw-p 00000000 00:00 0 [anon:.bss]
+70ead79000-70ead7d000 r--s 00000000 fc:00 282 /system/fonts/NotoSerifArmenian-Regular.ttf
+70ead7d000-70ead82000 r--s 00000000 fc:00 288 /system/fonts/NotoSerifHebrew-Bold.ttf
+70ead82000-70ead83000 r-xp 00000000 fc:00 2680 /system/lib64/android.hardware.media@1.0.so
+70ead83000-70eada1000 ---p 00000000 00:00 0
+70eada1000-70eada2000 r--p 0000f000 fc:00 2680 /system/lib64/android.hardware.media@1.0.so
+70eada2000-70eada3000 rw-p 00010000 fc:00 2680 /system/lib64/android.hardware.media@1.0.so
+70eada3000-70eada8000 r--s 00000000 fc:00 248 /system/fonts/NotoSerifHebrew-Regular.ttf
+70eada8000-70eadb9000 r--s 00000000 fc:00 252 /system/fonts/CutiveMono.ttf
+70eadb9000-70eadd9000 r--s 00000000 00:10 16641 /dev/__properties__/u:object_r:radio_prop:s0
+70eadd9000-70eadda000 r-xp 00000000 fc:00 2533 /system/lib64/android.hardware.graphics.common@1.0.so
+70eadda000-70eadf8000 ---p 00000000 00:00 0
+70eadf8000-70eadf9000 r--p 0000f000 fc:00 2533 /system/lib64/android.hardware.graphics.common@1.0.so
+70eadf9000-70eadfa000 rw-p 00010000 fc:00 2533 /system/lib64/android.hardware.graphics.common@1.0.so
+70eadfa000-70eadfb000 r--s 00000000 fc:00 1126 /system/usr/hyphen-data/hyph-hr.hyb
+70eadfb000-70eadfd000 r--s 00000000 fc:00 194 /system/fonts/NotoSansLisu-Regular.ttf
+70eadfd000-70eae18000 r--s 00000000 fc:00 201 /system/fonts/DroidSansMono.ttf
+70eae18000-70eae3b000 r-xp 00000000 fc:00 2925 /system/lib64/liblzma.so
+70eae3b000-70eae57000 ---p 00000000 00:00 0
+70eae57000-70eae58000 r--p 0002f000 fc:00 2925 /system/lib64/liblzma.so
+70eae58000-70eae59000 rw-p 00030000 fc:00 2925 /system/lib64/liblzma.so
+70eae59000-70eae5f000 rw-p 00000000 00:00 0 [anon:.bss]
+70eae5f000-70eae62000 r--s 00000000 fc:00 103 /system/fonts/NotoSansLimbu-Regular.ttf
+70eae62000-70eae67000 r--s 00000000 fc:00 236 /system/fonts/NotoSansHebrew-Bold.ttf
+70eae67000-70eae84000 r--s 001c2000 fc:00 990 /system/framework/ext.jar
+70eae84000-70eaea4000 rw-p 00000000 00:05 10269720 /dev/ashmem/dalvik-LinearAlloc (deleted)
+70eaea4000-70eaede000 r-xp 00000000 fc:00 2924 /system/lib64/libwilhelm.so
+70eaede000-70eaefa000 ---p 00000000 00:00 0
+70eaefa000-70eaeff000 r--p 0003b000 fc:00 2924 /system/lib64/libwilhelm.so
+70eaeff000-70eaf00000 rw-p 00040000 fc:00 2924 /system/lib64/libwilhelm.so
+70eaf00000-70eaf03000 r--s 00000000 fc:00 242 /system/fonts/NotoSansElbasan-Regular.otf
+70eaf03000-70eaf21000 r-xp 00000000 fc:00 2415 /system/lib64/libdrmframework.so
+70eaf21000-70eaf38000 ---p 00000000 00:00 0
+70eaf38000-70eaf3d000 r--p 0002b000 fc:00 2415 /system/lib64/libdrmframework.so
+70eaf3d000-70eaf3e000 rw-p 00030000 fc:00 2415 /system/lib64/libdrmframework.so
+70eaf3e000-70eaf43000 r--s 00000000 fc:00 70 /system/fonts/NotoSansHebrew-Regular.ttf
+70eaf43000-70eaf44000 ---p 00000000 00:00 0 [anon:thread signal stack guard]
+70eaf44000-70eaf48000 rw-p 00000000 00:00 0 [anon:thread signal stack]
+70eaf48000-70eaf49000 ---p 00000000 00:00 0 [anon:bionic TLS guard]
+70eaf49000-70eaf4c000 rw-p 00000000 00:00 0 [anon:bionic TLS]
+70eaf4c000-70eaf4d000 ---p 00000000 00:00 0 [anon:bionic TLS guard]
+70eaf4d000-70eaf4e000 ---p 00000000 00:00 0 [anon:thread signal stack guard]
+70eaf4e000-70eaf52000 rw-p 00000000 00:00 0 [anon:thread signal stack]
+70eaf52000-70eaf98000 r-xp 00000000 fc:00 2426 /system/lib64/libunwindstack.so
+70eaf98000-70eafb6000 ---p 00000000 00:00 0
+70eafb6000-70eafbd000 r--p 00049000 fc:00 2426 /system/lib64/libunwindstack.so
+70eafbd000-70eafbe000 rw-p 00050000 fc:00 2426 /system/lib64/libunwindstack.so
+70eafbe000-70eafc0000 r--s 00000000 fc:00 162 /system/fonts/NotoSansKayahLi-Regular.ttf
+70eafc0000-70eafe4000 r-xp 00000000 fc:00 2944 /system/lib64/libvulkan.so
+70eafe4000-70eaffc000 ---p 00000000 00:00 0
+70eaffc000-70eaffe000 r--p 0002e000 fc:00 2944 /system/lib64/libvulkan.so
+70eaffe000-70eafff000 rw-p 00030000 fc:00 2944 /system/lib64/libvulkan.so
+70eafff000-70eb001000 r--s 00000000 fc:00 180 /system/fonts/NotoSansInscriptionalParthian-Regular.ttf
+70eb001000-70eb01d000 r-xp 00000000 fc:00 2400 /system/lib64/libbufferhubqueue.so
+70eb01d000-70eb030000 ---p 00000000 00:00 0
+70eb030000-70eb031000 r--p 0001f000 fc:00 2400 /system/lib64/libbufferhubqueue.so
+70eb031000-70eb032000 rw-p 00020000 fc:00 2400 /system/lib64/libbufferhubqueue.so
+70eb032000-70eb036000 r--s 00000000 fc:00 269 /system/fonts/NotoSansArmenian-Bold.ttf
+70eb036000-70eb037000 ---p 00000000 00:00 0 [anon:bionic TLS guard]
+70eb037000-70eb03a000 rw-p 00000000 00:00 0 [anon:bionic TLS]
+70eb03a000-70eb03b000 ---p 00000000 00:00 0 [anon:bionic TLS guard]
+70eb03b000-70eb03c000 ---p 00000000 00:00 0 [anon:thread signal stack guard]
+70eb03c000-70eb040000 rw-p 00000000 00:00 0 [anon:thread signal stack]
+70eb040000-70eb042000 r-xp 00000000 fc:00 2935 /system/lib64/libhardware.so
+70eb042000-70eb05f000 ---p 00000000 00:00 0
+70eb05f000-70eb060000 r--p 0000f000 fc:00 2935 /system/lib64/libhardware.so
+70eb060000-70eb061000 rw-p 00010000 fc:00 2935 /system/lib64/libhardware.so
+70eb061000-70eb063000 r--s 00000000 fc:00 171 /system/fonts/NotoSansInscriptionalPahlavi-Regular.ttf
+70eb063000-70eb064000 ---p 00000000 00:00 0 [anon:bionic TLS guard]
+70eb064000-70eb067000 rw-p 00000000 00:00 0 [anon:bionic TLS]
+70eb067000-70eb068000 ---p 00000000 00:00 0 [anon:bionic TLS guard]
+70eb068000-70eb069000 ---p 00000000 00:00 0 [anon:thread signal stack guard]
+70eb069000-70eb06d000 rw-p 00000000 00:00 0 [anon:thread signal stack]
+70eb06d000-70eb06e000 ---p 00000000 00:00 0 [anon:bionic TLS guard]
+70eb06e000-70eb071000 rw-p 00000000 00:00 0 [anon:bionic TLS]
+70eb071000-70eb072000 ---p 00000000 00:00 0 [anon:bionic TLS guard]
+70eb072000-70eb073000 ---p 00000000 00:00 0 [anon:thread signal stack guard]
+70eb073000-70eb077000 rw-p 00000000 00:00 0 [anon:thread signal stack]
+70eb077000-70eb078000 ---p 00000000 00:00 0 [anon:bionic TLS guard]
+70eb078000-70eb07b000 rw-p 00000000 00:00 0 [anon:bionic TLS]
+70eb07b000-70eb07c000 ---p 00000000 00:00 0 [anon:bionic TLS guard]
+70eb07c000-70eb07d000 ---p 00000000 00:00 0 [anon:thread signal stack guard]
+70eb07d000-70eb081000 rw-p 00000000 00:00 0 [anon:thread signal stack]
+70eb081000-70eb082000 ---p 00000000 00:00 0 [anon:bionic TLS guard]
+70eb082000-70eb085000 rw-p 00000000 00:00 0 [anon:bionic TLS]
+70eb085000-70eb086000 ---p 00000000 00:00 0 [anon:bionic TLS guard]
+70eb086000-70eb09d000 r-xp 00000000 fc:00 2604 /system/lib64/libz.so
+70eb09d000-70eb0b5000 ---p 00000000 00:00 0
+70eb0b5000-70eb0b6000 r--p 0001f000 fc:00 2604 /system/lib64/libz.so
+70eb0b6000-70eb0b7000 rw-p 00020000 fc:00 2604 /system/lib64/libz.so
+70eb0b7000-70eb0bb000 r--s 00000000 fc:00 289 /system/fonts/NotoSansArmenian-Regular.ttf
+70eb0bb000-70eb0bc000 ---p 00000000 00:00 0 [anon:thread signal stack guard]
+70eb0bc000-70eb0c0000 rw-p 00000000 00:00 0 [anon:thread signal stack]
+70eb0c0000-70eb0c1000 ---p 00000000 00:00 0 [anon:bionic TLS guard]
+70eb0c1000-70eb0c4000 rw-p 00000000 00:00 0 [anon:bionic TLS]
+70eb0c4000-70eb0c5000 ---p 00000000 00:00 0 [anon:bionic TLS guard]
+70eb0c5000-70eb0c6000 ---p 00000000 00:00 0 [anon:thread signal stack guard]
+70eb0c6000-70eb0ca000 rw-p 00000000 00:00 0 [anon:thread signal stack]
+70eb0ca000-70eb0cb000 ---p 00000000 00:00 0 [anon:bionic TLS guard]
+70eb0cb000-70eb0ce000 rw-p 00000000 00:00 0 [anon:bionic TLS]
+70eb0ce000-70eb0cf000 ---p 00000000 00:00 0 [anon:bionic TLS guard]
+70eb0cf000-70eb0ef000 rw-p 00000000 00:05 10270988 /dev/ashmem/dalvik-LinearAlloc (deleted)
+70eb0ef000-70eb5bb000 r-xp 00000000 fc:00 2374 /system/lib64/libpdfium.so
+70eb5bb000-70eb5cf000 ---p 00000000 00:00 0
+70eb5cf000-70eb5e6000 r--p 004d9000 fc:00 2374 /system/lib64/libpdfium.so
+70eb5e6000-70eb5ea000 rw-p 004f0000 fc:00 2374 /system/lib64/libpdfium.so
+70eb5ea000-70eb5f1000 rw-p 00000000 00:00 0 [anon:.bss]
+70eb5f1000-70eb5f2000 r--s 00000000 fc:00 1094 /system/usr/hyphen-data/hyph-hi.hyb
+70eb5f2000-70eb5f6000 rw-p 00000000 00:05 10270982 /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb5f6000-70eb5fa000 rw-p 00000000 00:05 10270981 /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb5fa000-70eb5fe000 rw-p 00000000 00:05 10270980 /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb5fe000-70eb602000 rw-p 00000000 00:05 10270979 /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb602000-70eb606000 rw-p 00000000 00:05 10270978 /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb606000-70eb60a000 rw-p 00000000 00:05 10270977 /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb60a000-70eb60e000 rw-p 00000000 00:05 10270976 /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb60e000-70eb612000 rw-p 00000000 00:05 10270975 /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb612000-70eb616000 rw-p 00000000 00:05 10270974 /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb616000-70eb61a000 r-xp 00000000 fc:00 2479 /system/lib64/libspeexresampler.so
+70eb61a000-70eb635000 ---p 00000000 00:00 0
+70eb635000-70eb636000 r--p 0000f000 fc:00 2479 /system/lib64/libspeexresampler.so
+70eb636000-70eb637000 rw-p 00010000 fc:00 2479 /system/lib64/libspeexresampler.so
+70eb637000-70eb639000 r--s 00000000 fc:00 299 /system/fonts/NotoSansImperialAramaic-Regular.ttf
+70eb639000-70eb63d000 rw-p 00000000 00:05 10270973 /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb63d000-70eb641000 rw-p 00000000 00:05 10270972 /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb641000-70eb645000 rw-p 00000000 00:05 10270971 /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb645000-70eb649000 rw-p 00000000 00:05 10270970 /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb649000-70eb64d000 rw-p 00000000 00:05 10270969 /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb64d000-70eb651000 rw-p 00000000 00:05 10270968 /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb651000-70eb655000 rw-p 00000000 00:05 10270967 /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb655000-70eb659000 rw-p 00000000 00:05 10270966 /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb659000-70eb65d000 rw-p 00000000 00:05 10270965 /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb65d000-70eb661000 rw-p 00000000 00:05 10270964 /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb661000-70eb6c5000 r-xp 00000000 fc:00 2461 /system/lib64/libhidl-gen-utils.so
+70eb6c5000-70eb6df000 ---p 00000000 00:00 0
+70eb6df000-70eb6e1000 r--p 0006e000 fc:00 2461 /system/lib64/libhidl-gen-utils.so
+70eb6e1000-70eb6e2000 rw-p 00070000 fc:00 2461 /system/lib64/libhidl-gen-utils.so
+70eb6e2000-70eb6e6000 rw-p 00000000 00:05 10270963 /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb6e6000-70eb6ea000 rw-p 00000000 00:05 10270962 /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb6ea000-70eb6ee000 rw-p 00000000 00:05 10270961 /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb6ee000-70eb6f2000 rw-p 00000000 00:05 10270960 /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb6f2000-70eb6f6000 rw-p 00000000 00:05 10270959 /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb6f6000-70eb6fa000 rw-p 00000000 00:05 10270958 /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb6fa000-70eb6fe000 rw-p 00000000 00:05 10270957 /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb6fe000-70eb702000 rw-p 00000000 00:05 10270956 /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb702000-70eb706000 rw-p 00000000 00:05 10270955 /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb706000-70eb70a000 rw-p 00000000 00:05 10270954 /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb70a000-70eb70e000 rw-p 00000000 00:05 10270953 /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb70e000-70eb712000 rw-p 00000000 00:05 10270952 /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb712000-70eb71a000 r-xp 00000000 fc:00 2652 /system/lib64/libcamera_metadata.so
+70eb71a000-70eb72f000 ---p 00000000 00:00 0
+70eb72f000-70eb730000 r--p 0000f000 fc:00 2652 /system/lib64/libcamera_metadata.so
+70eb730000-70eb732000 rw-p 00010000 fc:00 2652 /system/lib64/libcamera_metadata.so
+70eb732000-70eb734000 r--s 00000000 fc:00 131 /system/fonts/NotoSansHanunoo-Regular.ttf
+70eb734000-70eb738000 rw-p 00000000 00:05 10270951 /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb738000-70eb73c000 rw-p 00000000 00:05 10270950 /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb73c000-70eb740000 rw-p 00000000 00:05 10270949 /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb740000-70eb744000 rw-p 00000000 00:05 10270948 /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb744000-70eb748000 rw-p 00000000 00:05 10270947 /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb748000-70eb74c000 rw-p 00000000 00:05 10270946 /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb74c000-70eb750000 rw-p 00000000 00:05 10270945 /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb750000-70eb754000 rw-p 00000000 00:05 10270944 /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb754000-70eb758000 rw-p 00000000 00:05 10270943 /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb758000-70eb75c000 rw-p 00000000 00:05 10270942 /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb75c000-70eb760000 rw-p 00000000 00:05 10270941 /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb760000-70eb764000 rw-p 00000000 00:05 10270940 /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb764000-70eb767000 rw-p 00000000 00:00 0 [anon:linker_alloc]
+70eb767000-70eb768000 r--p 00000000 00:00 0 [anon:linker_alloc]
+70eb768000-70eb76c000 rw-p 00000000 00:05 10270939 /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb76c000-70eb770000 rw-p 00000000 00:05 10270938 /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb770000-70eb771000 rw-p 00000000 00:00 0 [anon:linker_alloc]
+70eb771000-70eb774000 r--s 00000000 fc:00 231 /system/fonts/NotoSansDeseret-Regular.ttf
+70eb774000-70eb778000 rw-p 00000000 00:05 10270937 /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb778000-70eb77c000 rw-p 00000000 00:05 10270936 /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb77c000-70eb780000 rw-p 00000000 00:05 10270935 /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb780000-70eb784000 rw-p 00000000 00:05 10270934 /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb784000-70eb788000 rw-p 00000000 00:05 10270933 /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb788000-70eb78c000 rw-p 00000000 00:05 10270932 /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb78c000-70eb790000 rw-p 00000000 00:05 10270931 /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb790000-70eb794000 rw-p 00000000 00:05 10270930 /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb794000-70eb798000 rw-p 00000000 00:05 10270929 /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb798000-70eb79c000 rw-p 00000000 00:05 10270928 /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb79c000-70eb7a0000 rw-p 00000000 00:05 10270927 /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb7a0000-70eb7a1000 r--p 00000000 00:00 0 [anon:linker_alloc]
+70eb7a1000-70eb7a3000 r--s 00000000 fc:00 176 /system/fonts/NotoSansGothic-Regular.ttf
+70eb7a3000-70eb7a7000 rw-p 00000000 00:05 10270926 /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb7a7000-70eb7a8000 r--p 00000000 00:00 0 [anon:linker_alloc]
+70eb7a8000-70eb7a9000 r--s 00000000 fc:00 1109 /system/usr/hyphen-data/hyph-gu.hyb
+70eb7a9000-70eb7ad000 rw-p 00000000 00:05 10270925 /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb7ad000-70eb7ae000 r--p 00000000 00:00 0 [anon:linker_alloc]
+70eb7ae000-70eb7af000 rw-p 00000000 00:00 0 [anon:linker_alloc]
+70eb7af000-70eb7b0000 r--p 00000000 00:00 0 [anon:linker_alloc]
+70eb7b0000-70eb7b2000 r--s 00000000 fc:00 191 /system/fonts/NotoSansCypriot-Regular.ttf
+70eb7b2000-70eb7b6000 rw-p 00000000 00:05 10270924 /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb7b6000-70eb7ba000 rw-p 00000000 00:05 10270923 /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb7ba000-70eb7be000 rw-p 00000000 00:05 10270922 /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb7be000-70eb7c2000 rw-p 00000000 00:05 10270921 /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb7c2000-70eb7c6000 rw-p 00000000 00:05 10270920 /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb7c6000-70eb7ca000 rw-p 00000000 00:05 10270919 /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb7ca000-70eb7ce000 rw-p 00000000 00:05 10270918 /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb7ce000-70eb7d2000 rw-p 00000000 00:05 10270917 /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb7d2000-70eb7d6000 rw-p 00000000 00:05 10270916 /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb7d6000-70eb7d7000 rw-p 00000000 00:00 0 [anon:linker_alloc_small_objects]
+70eb7d7000-70eb7db000 rw-p 00000000 00:05 10270915 /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb7db000-70eb7df000 rw-p 00000000 00:05 10270914 /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb7df000-70eb7e3000 rw-p 00000000 00:05 10270913 /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb7e3000-70eb7e7000 rw-p 00000000 00:05 10270912 /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb7e7000-70eb7e8000 r--p 00000000 00:00 0 [anon:linker_alloc]
+70eb7e8000-70eb7ea000 r--s 00000000 fc:00 174 /system/fonts/NotoSansCarian-Regular.ttf
+70eb7ea000-70eb7ee000 rw-p 00000000 00:05 10270911 /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb7ee000-70eb7f2000 rw-p 00000000 00:05 10270910 /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb7f2000-70eb7f6000 rw-p 00000000 00:05 10270909 /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb7f6000-70eb7f7000 rw-p 00000000 00:00 0 [anon:linker_alloc]
+70eb7f7000-70eb7f8000 r--s 00000000 fc:00 1096 /system/usr/hyphen-data/hyph-eu.hyb
+70eb7f8000-70eb7fc000 rw-p 00000000 00:05 10270908 /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb7fc000-70eb800000 rw-p 00000000 00:05 10270907 /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb800000-70eb804000 rw-p 00000000 00:05 10270906 /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb804000-70eb808000 rw-p 00000000 00:05 10270905 /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb808000-70eb80c000 rw-p 00000000 00:05 10270904 /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb80c000-70eb810000 rw-p 00000000 00:05 10270903 /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb810000-70eb814000 rw-p 00000000 00:05 10270902 /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb814000-70eb815000 rw-p 00000000 00:00 0 [anon:linker_alloc_vector]
+70eb815000-70eb819000 rw-p 00000000 00:05 10270901 /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb819000-70eb81d000 rw-p 00000000 00:05 10270900 /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb81d000-70eb81e000 rw-p 00000000 00:00 0 [anon:linker_alloc]
+70eb81e000-70eb822000 rw-p 00000000 00:05 10270899 /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb822000-70eb826000 rw-p 00000000 00:05 10270898 /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb826000-70eb82a000 rw-p 00000000 00:05 10270897 /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb82a000-70eb82e000 rw-p 00000000 00:05 10270896 /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb82e000-70eb832000 rw-p 00000000 00:05 10270895 /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb832000-70eb836000 rw-p 00000000 00:05 10270894 /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb836000-70eb837000 r--p 00000000 00:00 0 [anon:linker_alloc]
+70eb837000-70eb83b000 rw-p 00000000 00:05 10270893 /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb83b000-70eb83f000 rw-p 00000000 00:05 10270892 /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb83f000-70eb843000 rw-p 00000000 00:05 10270891 /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb843000-70eb847000 rw-p 00000000 00:05 10270890 /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb847000-70eb84b000 rw-p 00000000 00:05 10270889 /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb84b000-70eb84f000 rw-p 00000000 00:05 10270888 /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb84f000-70eb850000 rw-p 00000000 00:00 0 [anon:linker_alloc]
+70eb850000-70eb854000 rw-p 00000000 00:05 10270887 /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb854000-70eb858000 rw-p 00000000 00:05 10270886 /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb858000-70eb85c000 rw-p 00000000 00:05 10270885 /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb85c000-70eb860000 rw-p 00000000 00:05 10270884 /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb860000-70eb864000 rw-p 00000000 00:05 10270883 /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb864000-70eb868000 rw-p 00000000 00:05 10270882 /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb868000-70eb869000 r--p 00000000 00:00 0 [anon:linker_alloc]
+70eb869000-70eb86d000 rw-p 00000000 00:05 10270881 /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb86d000-70eb871000 rw-p 00000000 00:05 10270880 /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb871000-70eb875000 rw-p 00000000 00:05 10270879 /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb875000-70eb879000 rw-p 00000000 00:05 10270878 /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb879000-70eb87d000 rw-p 00000000 00:05 10270877 /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb87d000-70eb881000 rw-p 00000000 00:05 10270876 /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb881000-70eb885000 rw-p 00000000 00:05 10270875 /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb885000-70eb889000 rw-p 00000000 00:05 10270874 /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb889000-70eb88d000 rw-p 00000000 00:05 10270873 /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb88d000-70eb891000 rw-p 00000000 00:05 10270872 /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb891000-70eb892000 r--p 00000000 00:00 0 [anon:linker_alloc]
+70eb892000-70eb896000 rw-p 00000000 00:05 10270871 /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb896000-70eb89a000 rw-p 00000000 00:05 10270870 /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb89a000-70eb89b000 rw-p 00000000 00:00 0 [anon:linker_alloc_vector]
+70eb89b000-70eb89c000 rw-p 00000000 00:00 0 [anon:linker_alloc_small_objects]
+70eb89c000-70eb8a0000 rw-p 00000000 00:05 10270869 /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb8a0000-70eb8a4000 rw-p 00000000 00:05 10270868 /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb8a4000-70eb8a5000 r--p 00000000 00:00 0 [anon:atexit handlers]
+70eb8a5000-70eb8a9000 rw-p 00000000 00:05 10270867 /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb8a9000-70eb8ad000 rw-p 00000000 00:05 10270866 /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb8ad000-70eb8b1000 rw-p 00000000 00:05 10270865 /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb8b1000-70eb8b5000 rw-p 00000000 00:05 10270864 /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb8b5000-70eb8b9000 rw-p 00000000 00:05 10270863 /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb8b9000-70eb8bd000 rw-p 00000000 00:05 10270862 /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb8bd000-70eb8be000 rw-p 00000000 00:00 0 [anon:linker_alloc]
+70eb8be000-70eb8c1000 r--s 00000000 fc:00 168 /system/fonts/NotoSansAvestan-Regular.ttf
+70eb8c1000-70eb8c5000 rw-p 00000000 00:05 10270861 /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb8c5000-70eb8c9000 rw-p 00000000 00:05 10270860 /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb8c9000-70eb8cd000 rw-p 00000000 00:05 10270859 /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb8cd000-70eb8d1000 rw-p 00000000 00:05 10270858 /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb8d1000-70eb8d5000 rw-p 00000000 00:05 10270857 /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb8d5000-70eb8d7000 r--p 00000000 00:00 0 [anon:linker_alloc]
+70eb8d7000-70eb8db000 rw-p 00000000 00:05 10270856 /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb8db000-70eb8df000 rw-p 00000000 00:05 10270855 /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb8df000-70eb8e3000 rw-p 00000000 00:05 10270854 /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb8e3000-70eb8e7000 rw-p 00000000 00:05 10270853 /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb8e7000-70eb8eb000 rw-p 00000000 00:05 10270852 /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb8eb000-70eb8ec000 r--p 00000000 00:00 0 [anon:linker_alloc]
+70eb8ec000-70eb8ed000 r--s 00000000 fc:00 1099 /system/usr/hyphen-data/hyph-bn.hyb
+70eb8ed000-70eb8f1000 rw-p 00000000 00:05 10270851 /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb8f1000-70eb8f5000 rw-p 00000000 00:05 10270850 /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb8f5000-70eb8f9000 rw-p 00000000 00:05 10270849 /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb8f9000-70eb8fd000 rw-p 00000000 00:05 10270848 /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb8fd000-70eb901000 rw-p 00000000 00:05 10270847 /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb901000-70eb905000 rw-p 00000000 00:05 10270846 /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb905000-70eb909000 rw-p 00000000 00:05 10270845 /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb909000-70eb90d000 rw-p 00000000 00:05 10270844 /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb90d000-70eb911000 rw-p 00000000 00:05 10270843 /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb911000-70eb915000 rw-p 00000000 00:05 10270842 /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb915000-70eb916000 rw-p 00000000 00:00 0 [anon:linker_alloc]
+70eb916000-70eb917000 r--s 00000000 fc:00 1114 /system/usr/hyphen-data/hyph-bg.hyb
+70eb917000-70eb91b000 rw-p 00000000 00:05 10270841 /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb91b000-70eb91c000 r--p 00000000 00:00 0 [anon:linker_alloc]
+70eb91c000-70eb91d000 r--s 00000000 fc:00 1133 /system/usr/hyphen-data/hyph-as.hyb
+70eb91d000-70eb921000 rw-p 00000000 00:05 10270840 /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb921000-70eb925000 rw-p 00000000 00:05 10270839 /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb925000-70eb926000 rw-p 00000000 00:00 0 [anon:linker_alloc_small_objects]
+70eb926000-70eb927000 r--p 00000000 00:00 0 [anon:linker_alloc]
+70eb927000-70eb929000 r--s 00000000 fc:00 203 /system/fonts/NotoSansBuhid-Regular.ttf
+70eb929000-70eb92d000 rw-p 00000000 00:05 10270838 /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb92d000-70eb931000 rw-p 00000000 00:05 10270837 /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb931000-70eb935000 rw-p 00000000 00:05 10270836 /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb935000-70eb939000 rw-p 00000000 00:05 10270835 /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb939000-70eb93d000 rw-p 00000000 00:05 10270834 /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb93d000-70eb941000 rw-p 00000000 00:05 10270833 /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb941000-70eb945000 rw-p 00000000 00:05 10270832 /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb945000-70eb949000 rw-p 00000000 00:05 10270831 /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb949000-70eb94d000 rw-p 00000000 00:05 10270830 /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb94d000-70eb951000 rw-p 00000000 00:05 10270829 /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb951000-70eb991000 rw-p 00000000 00:05 10270722 /dev/ashmem/dalvik-mark stack (deleted)
+70eb991000-70eb992000 rw-p 00000000 00:00 0 [anon:linker_alloc]
+70eb992000-70eb996000 rw-p 00000000 00:05 10270828 /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb996000-70eb99a000 rw-p 00000000 00:05 10270827 /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb99a000-70eb99e000 rw-p 00000000 00:05 10270826 /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb99e000-70eb9a2000 rw-p 00000000 00:05 10270825 /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb9a2000-70eb9a4000 r--p 00000000 00:00 0 [anon:linker_alloc]
+70eb9a4000-70eb9a8000 rw-p 00000000 00:05 10270824 /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb9a8000-70eb9ac000 rw-p 00000000 00:05 10270823 /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb9ac000-70eb9b0000 rw-p 00000000 00:05 10270822 /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb9b0000-70eb9b1000 r--p 00000000 00:00 0 [anon:linker_alloc]
+70eb9b1000-70eb9b2000 r--s 00021000 fc:01 1180 /vendor/overlay/framework-res__auto_generated_rro.apk
+70eb9b2000-70eb9b6000 rw-p 00000000 00:05 10270821 /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb9b6000-70eb9ba000 rw-p 00000000 00:05 10270820 /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb9ba000-70eb9be000 rw-p 00000000 00:05 10270819 /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb9be000-70eb9c2000 rw-p 00000000 00:05 10270818 /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb9c2000-70eb9c6000 rw-p 00000000 00:05 10270817 /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb9c6000-70eb9ca000 rw-p 00000000 00:05 10270816 /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb9ca000-70eb9ce000 rw-p 00000000 00:05 10270815 /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb9ce000-70eb9cf000 rw-p 00000000 00:00 0 [anon:linker_alloc]
+70eb9cf000-70eb9d1000 r--s 00000000 fc:00 213 /system/fonts/NotoSansBuginese-Regular.ttf
+70eb9d1000-70eb9d5000 rw-p 00000000 00:05 10270814 /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb9d5000-70eb9d9000 rw-p 00000000 00:05 10270813 /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb9d9000-70eb9dd000 rw-p 00000000 00:05 10270812 /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb9dd000-70eb9e1000 rw-p 00000000 00:05 10270811 /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb9e1000-70eb9e5000 rw-p 00000000 00:05 10270810 /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb9e5000-70eb9e9000 rw-p 00000000 00:05 10270809 /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb9e9000-70eb9ed000 rw-p 00000000 00:05 10270808 /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb9ed000-70eb9f1000 rw-p 00000000 00:05 10270807 /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb9f1000-70eb9f5000 rw-p 00000000 00:05 10270806 /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb9f5000-70eb9f6000 r--p 00000000 00:00 0 [anon:linker_alloc]
+70eb9f6000-70eb9f8000 rw-p 00000000 00:05 10271002 /dev/ashmem/dalvik-indirect ref table (deleted)
+70eb9f8000-70eb9fc000 rw-p 00000000 00:05 10270805 /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb9fc000-70eb9fd000 rw-p 00000000 00:00 0 [anon:linker_alloc]
+70eb9fd000-70eb9ff000 rw-p 00000000 00:05 10270999 /dev/ashmem/dalvik-indirect ref table (deleted)
+70eb9ff000-70eba00000 r--s 00000000 fc:00 983 /system/framework/com.google.vr.platform.jar
+70eba00000-70eba04000 rw-p 00000000 00:05 10270804 /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eba04000-70eba08000 rw-p 00000000 00:05 10270803 /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eba08000-70eba0c000 rw-p 00000000 00:05 10270802 /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eba0c000-70eba10000 rw-p 00000000 00:05 10270801 /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eba10000-70eba14000 rw-p 00000000 00:05 10270800 /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eba14000-70eba18000 rw-p 00000000 00:05 10270799 /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eba18000-70eba1c000 rw-p 00000000 00:05 10270798 /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eba1c000-70eba20000 rw-p 00000000 00:05 10270797 /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eba20000-70eba24000 rw-p 00000000 00:05 10270796 /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eba24000-70eba28000 rw-p 00000000 00:05 10270795 /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eba28000-70eba2c000 rw-p 00000000 00:05 10270794 /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eba2c000-70eba2d000 rw-p 00000000 00:00 0 [anon:linker_alloc]
+70eba2d000-70eba2e000 r--s 00000000 fc:00 881 /system/framework/android.test.base.jar
+70eba2e000-70eba2f000 r--s 00000000 fc:00 707 /system/framework/framework-oahl-backward-compatibility.jar
+70eba2f000-70eba30000 r--s 00000000 fc:00 705 /system/framework/android.hidl.manager-V1.0-java.jar
+70eba30000-70eba34000 rw-p 00000000 00:05 10270793 /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eba34000-70eba38000 rw-p 00000000 00:05 10270792 /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eba38000-70eba3c000 rw-p 00000000 00:05 10270791 /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eba3c000-70eba40000 rw-p 00000000 00:05 10270790 /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eba40000-70eba44000 rw-p 00000000 00:05 10270789 /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eba44000-70eba48000 rw-p 00000000 00:05 10270788 /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eba48000-70eba4c000 rw-p 00000000 00:05 10270787 /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eba4c000-70eba50000 rw-p 00000000 00:05 10270786 /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eba50000-70eba52000 r--p 00000000 00:00 0 [anon:linker_alloc]
+70eba52000-70eba53000 r--s 00000000 fc:00 971 /system/framework/android.hidl.base-V1.0-java.jar
+70eba53000-70eba57000 rw-p 00000000 00:05 10270785 /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eba57000-70eba5b000 rw-p 00000000 00:05 10270784 /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eba5b000-70eba5f000 rw-p 00000000 00:05 10270783 /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eba5f000-70eba63000 rw-p 00000000 00:05 10270782 /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eba63000-70eba64000 rw-p 00000000 00:00 0 [anon:linker_alloc]
+70eba64000-70eba65000 r--s 00000000 fc:00 889 /system/framework/ims-common.jar
+70eba65000-70eba69000 rw-p 00000000 00:05 10270781 /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eba69000-70eba6d000 rw-p 00000000 00:05 10270780 /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eba6d000-70eba71000 rw-p 00000000 00:05 10270779 /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eba71000-70eba75000 rw-p 00000000 00:05 10270778 /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eba75000-70eba95000 rw-p 00000000 00:05 10267647 /dev/ashmem/dalvik-large marked objects (deleted)
+70eba95000-70ebab5000 rw-p 00000000 00:05 10267646 /dev/ashmem/dalvik-large live objects (deleted)
+70ebab5000-70ebab6000 r--p 00000000 00:00 0 [anon:linker_alloc]
+70ebab6000-70ebab7000 rw-p 00000000 00:00 0 [anon:linker_alloc]
+70ebab7000-70ebabb000 rw-p 00000000 00:05 10270777 /dev/ashmem/dalvik-thread local mark stack (deleted)
+70ebabb000-70ebadb000 r--s 00000000 00:10 16603 /dev/__properties__/u:object_r:exported_fingerprint_prop:s0
+70ebadb000-70ebadc000 r--p 00000000 00:00 0 [anon:linker_alloc]
+70ebadc000-70ebadd000 r--s 00000000 fc:00 878 /system/framework/voip-common.jar
+70ebadd000-70ebadf000 rw-p 00000000 00:05 10270995 /dev/ashmem/dalvik-indirect ref table (deleted)
+70ebadf000-70ebae3000 rw-p 00000000 00:05 10270776 /dev/ashmem/dalvik-thread local mark stack (deleted)
+70ebae3000-70ebae7000 rw-p 00000000 00:05 10270775 /dev/ashmem/dalvik-thread local mark stack (deleted)
+70ebae7000-70ebaeb000 rw-p 00000000 00:05 10270774 /dev/ashmem/dalvik-thread local mark stack (deleted)
+70ebaeb000-70ebaef000 rw-p 00000000 00:05 10270773 /dev/ashmem/dalvik-thread local mark stack (deleted)
+70ebaef000-70ebb0f000 r--s 00000000 00:10 16582 /dev/__properties__/u:object_r:debug_prop:s0
+70ebb0f000-70ebb10000 rw-p 00000000 00:00 0 [anon:linker_alloc]
+70ebb10000-70ebb11000 r--s 00000000 fc:00 703 /system/framework/telephony-common.jar
+70ebb11000-70ebb13000 rw-p 00000000 00:05 10270994 /dev/ashmem/dalvik-indirect ref table (deleted)
+70ebb13000-70ebb17000 rw-p 00000000 00:05 10270772 /dev/ashmem/dalvik-thread local mark stack (deleted)
+70ebb17000-70ebb19000 r--p 00000000 00:00 0 [anon:linker_alloc]
+70ebb19000-70ebb1d000 rw-p 00000000 00:05 10270771 /dev/ashmem/dalvik-thread local mark stack (deleted)
+70ebb1d000-70ebb3d000 r--s 00000000 00:10 16600 /dev/__properties__/u:object_r:exported_default_prop:s0
+70ebb3d000-70ebb5d000 r--s 00000000 00:10 16650 /dev/__properties__/u:object_r:system_prop:s0
+70ebb5d000-70ebb7d000 r--s 00000000 00:10 16610 /dev/__properties__/u:object_r:exported_vold_prop:s0
+70ebb7d000-70ebb9d000 r--s 00000000 00:10 16598 /dev/__properties__/u:object_r:exported_config_prop:s0
+70ebb9d000-70ebb9e000 rw-p 00000000 00:00 0 [anon:linker_alloc]
+70ebb9e000-70ebba2000 rw-p 00000000 00:05 10270770 /dev/ashmem/dalvik-thread local mark stack (deleted)
+70ebba2000-70ebba6000 rw-p 00000000 00:05 10270769 /dev/ashmem/dalvik-thread local mark stack (deleted)
+70ebba6000-70ebba7000 r--p 00000000 00:00 0 [anon:linker_alloc]
+70ebba7000-70ebba8000 r--s 00000000 fc:00 1004 /system/framework/framework.jar
+70ebba8000-70ebbac000 rw-p 00000000 00:05 10270768 /dev/ashmem/dalvik-thread local mark stack (deleted)
+70ebbac000-70ebbb0000 rw-p 00000000 00:05 10270767 /dev/ashmem/dalvik-thread local mark stack (deleted)
+70ebbb0000-70ebbb4000 rw-p 00000000 00:05 10270766 /dev/ashmem/dalvik-thread local mark stack (deleted)
+70ebbb4000-70ebbb8000 rw-p 00000000 00:05 10270765 /dev/ashmem/dalvik-thread local mark stack (deleted)
+70ebbb8000-70ebbbc000 rw-p 00000000 00:05 10270764 /dev/ashmem/dalvik-thread local mark stack (deleted)
+70ebbbc000-70ebbc0000 rw-p 00000000 00:05 10270763 /dev/ashmem/dalvik-thread local mark stack (deleted)
+70ebbc0000-70ebbc4000 rw-p 00000000 00:05 10270762 /dev/ashmem/dalvik-thread local mark stack (deleted)
+70ebbc4000-70ebbe4000 r--s 00000000 00:10 16581 /dev/__properties__/u:object_r:dalvik_prop:s0
+70ebbe4000-70ebbe5000 rw-p 00000000 00:00 0 [anon:linker_alloc]
+70ebbe5000-70ebbe6000 r--s 00004000 fc:00 877 /system/framework/apache-xml.jar
+70ebbe6000-70ebbe8000 rw-p 00000000 00:05 10270993 /dev/ashmem/dalvik-indirect ref table (deleted)
+70ebbe8000-70ebbec000 rw-p 00000000 00:05 10270761 /dev/ashmem/dalvik-thread local mark stack (deleted)
+70ebbec000-70ebbf0000 rw-p 00000000 00:05 10270760 /dev/ashmem/dalvik-thread local mark stack (deleted)
+70ebbf0000-70ebbf4000 rw-p 00000000 00:05 10270759 /dev/ashmem/dalvik-thread local mark stack (deleted)
+70ebbf4000-70ebbf8000 rw-p 00000000 00:05 10270758 /dev/ashmem/dalvik-thread local mark stack (deleted)
+70ebbf8000-70ebbf9000 r--p 00000000 00:00 0 [anon:linker_alloc]
+70ebbf9000-70ebbfa000 r--s 00000000 fc:00 968 /system/framework/bouncycastle.jar
+70ebbfa000-70ebbfc000 rw-p 00000000 00:05 10270992 /dev/ashmem/dalvik-indirect ref table (deleted)
+70ebbfc000-70ebc00000 rw-p 00000000 00:05 10270757 /dev/ashmem/dalvik-thread local mark stack (deleted)
+70ebc00000-70ebc04000 rw-p 00000000 00:05 10270756 /dev/ashmem/dalvik-thread local mark stack (deleted)
+70ebc04000-70ebc08000 rw-p 00000000 00:05 10270755 /dev/ashmem/dalvik-thread local mark stack (deleted)
+70ebc08000-70ebc0c000 rw-p 00000000 00:05 10270754 /dev/ashmem/dalvik-thread local mark stack (deleted)
+70ebc0c000-70ebc10000 rw-p 00000000 00:05 10270753 /dev/ashmem/dalvik-thread local mark stack (deleted)
+70ebc10000-70ebc14000 rw-p 00000000 00:05 10270752 /dev/ashmem/dalvik-thread local mark stack (deleted)
+70ebc14000-70ebc15000 rw-p 00000000 00:00 0 [anon:linker_alloc]
+70ebc15000-70ebc16000 r--s 00000000 fc:00 960 /system/framework/okhttp.jar
+70ebc16000-70ebc1a000 rw-p 00000000 00:05 10270751 /dev/ashmem/dalvik-thread local mark stack (deleted)
+70ebc1a000-70ebc1e000 rw-p 00000000 00:05 10270750 /dev/ashmem/dalvik-thread local mark stack (deleted)
+70ebc1e000-70ebc3e000 r--s 00000000 00:10 16584 /dev/__properties__/u:object_r:default_prop:s0
+70ebc3e000-70ebc3f000 r--p 00000000 00:00 0 [anon:linker_alloc]
+70ebc3f000-70ebc40000 r--s 00000000 fc:00 974 /system/framework/conscrypt.jar
+70ebc40000-70ebc42000 rw-p 00000000 00:05 10269719 /dev/ashmem/dalvik-indirect ref table (deleted)
+70ebc42000-70ebc46000 rw-p 00000000 00:05 10270749 /dev/ashmem/dalvik-thread local mark stack (deleted)
+70ebc46000-70ebc4a000 rw-p 00000000 00:05 10270748 /dev/ashmem/dalvik-thread local mark stack (deleted)
+70ebc4a000-70ebc4e000 rw-p 00000000 00:05 10270747 /dev/ashmem/dalvik-thread local mark stack (deleted)
+70ebc4e000-70ebc4f000 rw-p 00000000 00:00 0 [anon:linker_alloc]
+70ebc4f000-70ebc51000 rw-p 00000000 00:05 10269718 /dev/ashmem/dalvik-indirect ref table (deleted)
+70ebc51000-70ebc55000 rw-p 00000000 00:05 10270746 /dev/ashmem/dalvik-thread local mark stack (deleted)
+70ebc55000-70ebc59000 rw-p 00000000 00:05 10270745 /dev/ashmem/dalvik-thread local mark stack (deleted)
+70ebc59000-70ebc5d000 rw-p 00000000 00:05 10270744 /dev/ashmem/dalvik-thread local mark stack (deleted)
+70ebc5d000-70ebc7d000 r--s 00000000 00:10 16599 /dev/__properties__/u:object_r:exported_dalvik_prop:s0
+70ebc7d000-70ebc7e000 rw-p 00000000 00:00 0 [anon:linker_alloc]
+70ebc7e000-70ebc7f000 r--p 00000000 00:00 0 [anon:linker_alloc]
+70ebc7f000-70ebc80000 r--s 00004000 fc:00 963 /system/framework/core-libart.jar
+70ebc80000-70ebc81000 r--p 00000000 00:00 0 [anon:linker_alloc]
+70ebc81000-70ebc85000 rw-p 00000000 00:05 10270743 /dev/ashmem/dalvik-thread local mark stack (deleted)
+70ebc85000-70ebc89000 rw-p 00000000 00:05 10270742 /dev/ashmem/dalvik-thread local mark stack (deleted)
+70ebc89000-70ebc8a000 rw-p 00000000 00:00 0 [anon:linker_alloc_small_objects]
+70ebc8a000-70ebc8c000 r--p 00000000 00:00 0 [anon:linker_alloc]
+70ebc8c000-70ebc8d000 r--s 0001e000 fc:00 699 /system/framework/core-oj.jar
+70ebc8d000-70ebc91000 rw-p 00000000 00:05 10270741 /dev/ashmem/dalvik-thread local mark stack (deleted)
+70ebc91000-70ebc95000 rw-p 00000000 00:05 10270740 /dev/ashmem/dalvik-thread local mark stack (deleted)
+70ebc95000-70ebc99000 rw-p 00000000 00:05 10270739 /dev/ashmem/dalvik-thread local mark stack (deleted)
+70ebc99000-70ebc9b000 r--p 00000000 00:00 0 [anon:linker_alloc]
+70ebc9b000-70ebc9c000 rw-p 00000000 00:00 0 [anon:linker_alloc]
+70ebc9c000-70ebca0000 rw-p 00000000 00:05 10270738 /dev/ashmem/dalvik-thread local mark stack (deleted)
+70ebca0000-70ebca4000 rw-p 00000000 00:05 10270737 /dev/ashmem/dalvik-thread local mark stack (deleted)
+70ebca4000-70ebca8000 rw-p 00000000 00:05 10270736 /dev/ashmem/dalvik-thread local mark stack (deleted)
+70ebca8000-70ebcac000 rw-p 00000000 00:05 10270735 /dev/ashmem/dalvik-thread local mark stack (deleted)
+70ebcac000-70ebcb0000 rw-p 00000000 00:05 10270734 /dev/ashmem/dalvik-thread local mark stack (deleted)
+70ebcb0000-70ebcd0000 r--s 00000000 00:10 16592 /dev/__properties__/u:object_r:exported2_system_prop:s0
+70ebcd0000-70ebcd1000 rw-p 00000000 00:00 0 [anon:linker_alloc]
+70ebcd1000-70ebcd5000 rw-p 00000000 00:05 10270733 /dev/ashmem/dalvik-thread local mark stack (deleted)
+70ebcd5000-70ebcd9000 rw-p 00000000 00:05 10270732 /dev/ashmem/dalvik-thread local mark stack (deleted)
+70ebcd9000-70ebcdd000 rw-p 00000000 00:05 10270731 /dev/ashmem/dalvik-thread local mark stack (deleted)
+70ebcdd000-70ebce1000 rw-p 00000000 00:05 10270730 /dev/ashmem/dalvik-thread local mark stack (deleted)
+70ebce1000-70ebce5000 rw-p 00000000 00:05 10270729 /dev/ashmem/dalvik-thread local mark stack (deleted)
+70ebce5000-70ebce9000 rw-p 00000000 00:05 10270728 /dev/ashmem/dalvik-thread local mark stack (deleted)
+70ebce9000-70ebcea000 r--p 00000000 00:00 0 [anon:linker_alloc]
+70ebcea000-70ebcec000 rw-p 00000000 00:05 10270987 /dev/ashmem/dalvik-indirect ref table (deleted)
+70ebcec000-70ebcf9000 r--p 00646000 103:1d 639532 /data/dalvik-cache/arm64/system@framework@boot-framework.art
+70ebcf9000-70ebd19000 r--s 00000000 00:10 16620 /dev/__properties__/u:object_r:log_tag_prop:s0
+70ebd19000-70ebd39000 r--s 00000000 00:10 16621 /dev/__properties__/u:object_r:logd_prop:s0
+70ebd39000-70ebd3a000 rw-p 00000000 00:00 0 [anon:linker_alloc]
+70ebd3a000-70ebd3b000 r--p 00000000 00:00 0 [anon:linker_alloc]
+70ebd3b000-70ebd3f000 rw-p 00000000 00:05 10270727 /dev/ashmem/dalvik-thread local mark stack (deleted)
+70ebd3f000-70ebd40000 r--p 00002000 103:1d 639556 /data/dalvik-cache/arm64/system@framework@boot-com.google.vr.platform.art
+70ebd40000-70ebd41000 r--p 00005000 103:1d 639553 /data/dalvik-cache/arm64/system@framework@boot-android.test.base.art
+70ebd41000-70ebd42000 r--p 00000000 00:00 0 [anon:linker_alloc]
+70ebd42000-70ebd43000 r--p 00001000 103:1d 639550 /data/dalvik-cache/arm64/system@framework@boot-framework-oahl-backward-compatibility.art
+70ebd43000-70ebd44000 r--p 00005000 103:1d 639547 /data/dalvik-cache/arm64/system@framework@boot-android.hidl.manager-V1.0-java.art
+70ebd44000-70ebd45000 r--p 00003000 103:1d 639544 /data/dalvik-cache/arm64/system@framework@boot-android.hidl.base-V1.0-java.art
+70ebd45000-70ebd46000 r--p 00000000 00:00 0 [anon:linker_alloc]
+70ebd46000-70ebd47000 r--p 0000f000 103:1d 639541 /data/dalvik-cache/arm64/system@framework@boot-ims-common.art
+70ebd47000-70ebd48000 r--p 0000d000 103:1d 639538 /data/dalvik-cache/arm64/system@framework@boot-voip-common.art
+70ebd48000-70ebd4a000 r--p 0005e000 103:1d 639535 /data/dalvik-cache/arm64/system@framework@boot-telephony-common.art
+70ebd4a000-70ebd4b000 r--p 00040000 103:1d 639529 /data/dalvik-cache/arm64/system@framework@boot-ext.art
+70ebd4b000-70ebd4c000 r--p 0004a000 103:1d 639526 /data/dalvik-cache/arm64/system@framework@boot-apache-xml.art
+70ebd4c000-70ebd4d000 r--p 00046000 103:1d 639523 /data/dalvik-cache/arm64/system@framework@boot-bouncycastle.art
+70ebd4d000-70ebd4e000 r--p 00000000 00:00 0 [anon:linker_alloc]
+70ebd4e000-70ebd53000 r--p 00225000 103:1d 639511 /data/dalvik-cache/arm64/system@framework@boot.art
+70ebd53000-70ebd5a000 rw-p 00000000 fc:00 583 /system/etc/event-log-tags
+70ebd5a000-70ebd5b000 r--p 00000000 00:00 0 [anon:linker_alloc]
+70ebd5b000-70ebd5c000 r--p 0002e000 103:1d 639520 /data/dalvik-cache/arm64/system@framework@boot-okhttp.art
+70ebd5c000-70ebd5d000 r--p 00035000 103:1d 639517 /data/dalvik-cache/arm64/system@framework@boot-conscrypt.art
+70ebd5d000-70ebd5f000 r--p 000d0000 103:1d 639514 /data/dalvik-cache/arm64/system@framework@boot-core-libart.art
+70ebd5f000-70ebd62000 r--p 00000000 00:00 0 [anon:atexit handlers]
+70ebd62000-70ebd63000 rw-p 00000000 00:00 0
+70ebd63000-70ebd83000 r--s 00000000 00:10 16590 /dev/__properties__/u:object_r:exported2_default_prop:s0
+70ebd83000-70ebd84000 rw-p 00000000 00:00 0 [anon:linker_alloc]
+70ebd84000-70ebd89000 rw-p 00000000 00:00 0
+70ebd89000-70ebda9000 r--s 00000000 00:10 16669 /dev/__properties__/properties_serial
+70ebda9000-70ebdb3000 r--s 00000000 00:10 16560 /dev/__properties__/property_info
+70ebdb3000-70ebdb4000 rw-p 00000000 00:00 0 [anon:linker_alloc_vector]
+70ebdb4000-70ebdb5000 rw-p 00000000 00:00 0 [anon:linker_alloc_small_objects]
+70ebdb5000-70ebdb7000 rw-p 00000000 00:00 0 [anon:System property context nodes]
+70ebdb7000-70ebdb8000 rw-p 00000000 00:00 0 [anon:linker_alloc_vector]
+70ebdb8000-70ebdba000 rw-p 00000000 00:00 0 [anon:linker_alloc_small_objects]
+70ebdba000-70ebdbb000 rw-p 00000000 00:00 0 [anon:linker_alloc]
+70ebdbb000-70ebdbd000 rw-p 00000000 00:00 0 [anon:linker_alloc_small_objects]
+70ebdbd000-70ebdbe000 r--p 00000000 00:00 0 [anon:atexit handlers]
+70ebdbe000-70ebdbf000 r--p 00000000 00:00 0 [anon:linker_alloc]
+70ebdbf000-70ebdc0000 rw-p 00000000 00:00 0 [anon:linker_alloc_small_objects]
+70ebdc0000-70ebdc1000 rw-p 00000000 00:00 0 [anon:linker_alloc_vector]
+70ebdc1000-70ebdc2000 rw-p 00000000 00:00 0 [anon:linker_alloc_small_objects]
+70ebdc2000-70ebdc3000 rw-p 00000000 00:00 0 [anon:linker_alloc_vector]
+70ebdc3000-70ebdc5000 rw-p 00000000 00:00 0 [anon:linker_alloc_small_objects]
+70ebdc5000-70ebde5000 r--s 00000000 00:10 16600 /dev/__properties__/u:object_r:exported_default_prop:s0
+70ebde5000-70ebde6000 rw-p 00000000 00:00 0 [anon:linker_alloc_small_objects]
+70ebde6000-70ebde8000 r--p 00000000 00:00 0 [anon:linker_alloc]
+70ebde8000-70ebe08000 r--s 00000000 00:10 16582 /dev/__properties__/u:object_r:debug_prop:s0
+70ebe08000-70ebe09000 ---p 00000000 00:00 0
+70ebe09000-70ebe0a000 rw-p 00000000 00:00 0
+70ebe0a000-70ebe0b000 ---p 00000000 00:00 0
+70ebe0b000-70ebe2b000 r--s 00000000 00:10 16669 /dev/__properties__/properties_serial
+70ebe2b000-70ebe2d000 rw-p 00000000 00:00 0 [anon:System property context nodes]
+70ebe2d000-70ebf55000 r-xp 00000000 fc:00 3184 /system/bin/linker64
+70ebf55000-70ebf5f000 r--s 00000000 00:10 16560 /dev/__properties__/property_info
+70ebf5f000-70ebf60000 r--p 00000000 00:00 0 [anon:linker_alloc]
+70ebf60000-70ebf61000 rw-p 00000000 00:00 0 [anon:linker_alloc_vector]
+70ebf61000-70ebf62000 rw-p 00000000 00:00 0 [anon:linker_alloc_small_objects]
+70ebf62000-70ebf63000 rw-p 00000000 00:00 0 [anon:arc4random data]
+70ebf63000-70ebf64000 rw-p 00000000 00:00 0 [anon:linker_alloc_small_objects]
+70ebf64000-70ebf65000 r--p 00000000 00:00 0 [anon:atexit handlers]
+70ebf65000-70ebf66000 ---p 00000000 00:00 0 [anon:thread signal stack guard]
+70ebf66000-70ebf6a000 rw-p 00000000 00:00 0 [anon:thread signal stack]
+70ebf6a000-70ebf6b000 rw-p 00000000 00:00 0 [anon:arc4random data]
+70ebf6b000-70ebf6c000 ---p 00000000 00:00 0 [anon:bionic TLS guard]
+70ebf6c000-70ebf6f000 rw-p 00000000 00:00 0 [anon:bionic TLS]
+70ebf6f000-70ebf70000 ---p 00000000 00:00 0 [anon:bionic TLS guard]
+70ebf70000-70ebf71000 r--p 00000000 00:00 0 [vvar]
+70ebf71000-70ebf72000 r-xp 00000000 00:00 0 [vdso]
+70ebf72000-70ebf7d000 r--p 00135000 fc:00 3184 /system/bin/linker64
+70ebf7d000-70ebf7e000 rw-p 00140000 fc:00 3184 /system/bin/linker64
+70ebf7e000-70ebf81000 rw-p 00000000 00:00 0
+70ebf81000-70ebf82000 r--p 00000000 00:00 0
+70ebf82000-70ebf89000 rw-p 00000000 00:00 0
+7fc7df1000-7fc7df2000 ---p 00000000 00:00 0
+7fc7df2000-7fc85f1000 rw-p 00000000 00:00 0 [stack]
diff --git a/libsparse/include/sparse/sparse.h b/libsparse/include/sparse/sparse.h
index 356f65f..1b91ead 100644
--- a/libsparse/include/sparse/sparse.h
+++ b/libsparse/include/sparse/sparse.h
@@ -18,6 +18,7 @@
#define _LIBSPARSE_SPARSE_H_
#include <stdbool.h>
+#include <stddef.h>
#include <stdint.h>
#ifdef __cplusplus
@@ -26,6 +27,11 @@
struct sparse_file;
+// The callbacks in sparse_file_callback() and sparse_file_foreach_chunk() take
+// size_t as the length type (was `int` in past). This allows clients to keep
+// their codes compatibile with both versions as needed.
+#define SPARSE_CALLBACK_USES_SIZE_T
+
/**
* sparse_file_new - create a new sparse file cookie
*
@@ -201,7 +207,7 @@
* Returns 0 on success, negative errno on error.
*/
int sparse_file_callback(struct sparse_file *s, bool sparse, bool crc,
- int (*write)(void *priv, const void *data, int len), void *priv);
+ int (*write)(void *priv, const void *data, size_t len), void *priv);
/**
* sparse_file_foreach_chunk - call a callback for data blocks in sparse file
@@ -218,7 +224,7 @@
* Returns 0 on success, negative errno on error.
*/
int sparse_file_foreach_chunk(struct sparse_file *s, bool sparse, bool crc,
- int (*write)(void *priv, const void *data, int len, unsigned int block,
+ int (*write)(void *priv, const void *data, size_t len, unsigned int block,
unsigned int nr_blocks),
void *priv);
/**
diff --git a/libsparse/output_file.c b/libsparse/output_file.c
index 51e60ef..002ad27 100644
--- a/libsparse/output_file.c
+++ b/libsparse/output_file.c
@@ -109,7 +109,7 @@
struct output_file_callback {
struct output_file out;
void *priv;
- int (*write)(void *priv, const void *buf, int len);
+ int (*write)(void *priv, const void *buf, size_t len);
};
#define to_output_file_callback(_o) \
@@ -634,7 +634,8 @@
return &outn->out;
}
-struct output_file *output_file_open_callback(int (*write)(void *, const void *, int),
+struct output_file *output_file_open_callback(
+ int (*write)(void *, const void *, size_t),
void *priv, unsigned int block_size, int64_t len,
int gz __unused, int sparse, int chunks, int crc)
{
diff --git a/libsparse/output_file.h b/libsparse/output_file.h
index b67e94e..690f610 100644
--- a/libsparse/output_file.h
+++ b/libsparse/output_file.h
@@ -27,7 +27,8 @@
struct output_file *output_file_open_fd(int fd, unsigned int block_size, int64_t len,
int gz, int sparse, int chunks, int crc);
-struct output_file *output_file_open_callback(int (*write)(void *, const void *, int),
+struct output_file *output_file_open_callback(
+ int (*write)(void *, const void *, size_t),
void *priv, unsigned int block_size, int64_t len, int gz, int sparse,
int chunks, int crc);
int write_data_chunk(struct output_file *out, unsigned int len, void *data);
diff --git a/libsparse/sparse.c b/libsparse/sparse.c
index b175860..466435f 100644
--- a/libsparse/sparse.c
+++ b/libsparse/sparse.c
@@ -179,7 +179,7 @@
}
int sparse_file_callback(struct sparse_file *s, bool sparse, bool crc,
- int (*write)(void *priv, const void *data, int len), void *priv)
+ int (*write)(void *priv, const void *data, size_t len), void *priv)
{
int ret;
int chunks;
@@ -203,11 +203,11 @@
void *priv;
unsigned int block;
unsigned int nr_blocks;
- int (*write)(void *priv, const void *data, int len, unsigned int block,
- unsigned int nr_blocks);
+ int (*write)(void *priv, const void *data, size_t len,
+ unsigned int block, unsigned int nr_blocks);
};
-static int foreach_chunk_write(void *priv, const void *data, int len)
+static int foreach_chunk_write(void *priv, const void *data, size_t len)
{
struct chunk_data *chk = priv;
@@ -215,7 +215,7 @@
}
int sparse_file_foreach_chunk(struct sparse_file *s, bool sparse, bool crc,
- int (*write)(void *priv, const void *data, int len, unsigned int block,
+ int (*write)(void *priv, const void *data, size_t len, unsigned int block,
unsigned int nr_blocks),
void *priv)
{
@@ -250,7 +250,7 @@
return ret;
}
-static int out_counter_write(void *priv, const void *data __unused, int len)
+static int out_counter_write(void *priv, const void *data __unused, size_t len)
{
int64_t *count = priv;
*count += len;
diff --git a/libsync/include/ndk/sync.h b/libsync/include/ndk/sync.h
index 3c55783..a786d3e 100644
--- a/libsync/include/ndk/sync.h
+++ b/libsync/include/ndk/sync.h
@@ -14,6 +14,15 @@
* limitations under the License.
*/
+/**
+ * @addtogroup Sync
+ * @{
+ */
+
+/**
+ * @file sync.h
+ */
+
#ifndef ANDROID_SYNC_H
#define ANDROID_SYNC_H
@@ -86,3 +95,5 @@
__END_DECLS
#endif /* ANDROID_SYNC_H */
+
+/** @} */
diff --git a/libunwindstack/Android.bp b/libunwindstack/Android.bp
index 7b8111c..82f2e73 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: {
@@ -106,6 +110,10 @@
},
},
+ static_libs: [
+ "libprocinfo",
+ ],
+
shared_libs: [
"libbase",
"libdexfile",
@@ -114,79 +122,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 +132,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 +183,14 @@
"liblog",
"liblzma",
"libunwindstack",
+ "libdexfile",
],
static_libs: [
"libgmock",
],
- whole_static_libs: ["libunwindstack_dex_test"],
-
+ test_suites: ["device-tests"],
data: [
"tests/files/elf32.xz",
"tests/files/elf64.xz",
@@ -260,7 +200,9 @@
"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/offset_arm/*",
"tests/files/offline/straddle_arm/*",
"tests/files/offline/straddle_arm64/*",
],
diff --git a/libunwindstack/Elf.cpp b/libunwindstack/Elf.cpp
index 02f8a9a..3762107 100644
--- a/libunwindstack/Elf.cpp
+++ b/libunwindstack/Elf.cpp
@@ -160,14 +160,14 @@
}
// The relative pc is always relative to the start of the map from which it comes.
-bool Elf::Step(uint64_t rel_pc, uint64_t adjusted_rel_pc, uint64_t elf_offset, Regs* regs,
- Memory* process_memory, bool* finished) {
+bool Elf::Step(uint64_t rel_pc, uint64_t adjusted_rel_pc, Regs* regs, Memory* process_memory,
+ bool* finished) {
if (!valid_) {
return false;
}
// The relative pc expectd by StepIfSignalHandler is relative to the start of the elf.
- if (regs->StepIfSignalHandler(rel_pc + elf_offset, this, process_memory)) {
+ if (regs->StepIfSignalHandler(rel_pc, this, process_memory)) {
*finished = false;
return true;
}
diff --git a/libunwindstack/ElfInterface.cpp b/libunwindstack/ElfInterface.cpp
index 10afe33..4c05a1b 100644
--- a/libunwindstack/ElfInterface.cpp
+++ b/libunwindstack/ElfInterface.cpp
@@ -87,8 +87,8 @@
ISzAlloc alloc;
CXzUnpacker state;
- alloc.Alloc = [](void*, size_t size) { return malloc(size); };
- alloc.Free = [](void*, void* ptr) { return free(ptr); };
+ alloc.Alloc = [](ISzAllocPtr, size_t size) { return malloc(size); };
+ alloc.Free = [](ISzAllocPtr, void* ptr) { return free(ptr); };
XzUnpacker_Construct(&state, &alloc);
@@ -106,7 +106,7 @@
dst_remaining += 2 * gnu_debugdata_size_;
}
return_val = XzUnpacker_Code(&state, dst->GetPtr(dst_offset), &dst_remaining, &src[src_offset],
- &src_remaining, CODER_FINISH_ANY, &status);
+ &src_remaining, true, CODER_FINISH_ANY, &status);
src_offset += src_remaining;
dst_offset += dst_remaining;
} while (return_val == SZ_OK && status == CODER_STATUS_NOT_FINISHED);
diff --git a/libunwindstack/Maps.cpp b/libunwindstack/Maps.cpp
index 4c16212..bb682ea 100644
--- a/libunwindstack/Maps.cpp
+++ b/libunwindstack/Maps.cpp
@@ -24,7 +24,9 @@
#include <unistd.h>
#include <android-base/unique_fd.h>
+#include <procinfo/process_map.h>
+#include <algorithm>
#include <cctype>
#include <memory>
#include <string>
@@ -56,150 +58,16 @@
return nullptr;
}
-// Assumes that line does not end in '\n'.
-static MapInfo* InternalParseLine(const char* line) {
- // Do not use a sscanf implementation since it is not performant.
-
- // Example linux /proc/<pid>/maps lines:
- // 6f000000-6f01e000 rwxp 00000000 00:0c 16389419 /system/lib/libcomposer.so
- char* str;
- const char* old_str = line;
- uint64_t start = strtoull(old_str, &str, 16);
- if (old_str == str || *str++ != '-') {
- return nullptr;
- }
-
- old_str = str;
- uint64_t end = strtoull(old_str, &str, 16);
- if (old_str == str || !std::isspace(*str++)) {
- return nullptr;
- }
-
- while (std::isspace(*str)) {
- str++;
- }
-
- // Parse permissions data.
- if (*str == '\0') {
- return nullptr;
- }
- uint16_t flags = 0;
- if (*str == 'r') {
- flags |= PROT_READ;
- } else if (*str != '-') {
- return nullptr;
- }
- str++;
- if (*str == 'w') {
- flags |= PROT_WRITE;
- } else if (*str != '-') {
- return nullptr;
- }
- str++;
- if (*str == 'x') {
- flags |= PROT_EXEC;
- } else if (*str != '-') {
- return nullptr;
- }
- str++;
- if (*str != 'p' && *str != 's') {
- return nullptr;
- }
- str++;
-
- if (!std::isspace(*str++)) {
- return nullptr;
- }
-
- old_str = str;
- uint64_t offset = strtoull(old_str, &str, 16);
- if (old_str == str || !std::isspace(*str)) {
- return nullptr;
- }
-
- // Ignore the 00:00 values.
- old_str = str;
- (void)strtoull(old_str, &str, 16);
- if (old_str == str || *str++ != ':') {
- return nullptr;
- }
- if (std::isspace(*str)) {
- return nullptr;
- }
-
- // Skip the inode.
- old_str = str;
- (void)strtoull(str, &str, 16);
- if (old_str == str || !std::isspace(*str++)) {
- return nullptr;
- }
-
- // Skip decimal digit.
- old_str = str;
- (void)strtoull(old_str, &str, 10);
- if (old_str == str || (!std::isspace(*str) && *str != '\0')) {
- return nullptr;
- }
-
- while (std::isspace(*str)) {
- str++;
- }
- if (*str == '\0') {
- return new MapInfo(start, end, offset, flags, "");
- }
-
- // Save the name data.
- std::string name(str);
-
- // Mark a device map in /dev/ and not in /dev/ashmem/ specially.
- if (name.substr(0, 5) == "/dev/" && name.substr(5, 7) != "ashmem/") {
- flags |= MAPS_FLAGS_DEVICE_MAP;
- }
- return new MapInfo(start, end, offset, flags, name);
-}
-
bool Maps::Parse() {
- int fd = open(GetMapsFile().c_str(), O_RDONLY | O_CLOEXEC);
- if (fd == -1) {
- return false;
- }
-
- bool return_value = true;
- char buffer[2048];
- size_t leftover = 0;
- while (true) {
- ssize_t bytes = read(fd, &buffer[leftover], 2048 - leftover);
- if (bytes == -1) {
- return_value = false;
- break;
- }
- if (bytes == 0) {
- break;
- }
- bytes += leftover;
- char* line = buffer;
- while (bytes > 0) {
- char* newline = static_cast<char*>(memchr(line, '\n', bytes));
- if (newline == nullptr) {
- memmove(buffer, line, bytes);
- break;
- }
- *newline = '\0';
-
- MapInfo* map_info = InternalParseLine(line);
- if (map_info == nullptr) {
- return_value = false;
- break;
- }
- maps_.push_back(map_info);
-
- bytes -= newline - line + 1;
- line = newline + 1;
- }
- leftover = bytes;
- }
- close(fd);
- return return_value;
+ return android::procinfo::ReadMapFile(
+ GetMapsFile(),
+ [&](uint64_t start, uint64_t end, uint16_t flags, uint64_t pgoff, const char* name) {
+ // Mark a device map in /dev/ and not in /dev/ashmem/ specially.
+ if (strncmp(name, "/dev/", 5) == 0 && strncmp(name + 5, "ashmem/", 7) != 0) {
+ flags |= unwindstack::MAPS_FLAGS_DEVICE_MAP;
+ }
+ maps_.push_back(new MapInfo(start, end, pgoff, flags, name));
+ });
}
void Maps::Add(uint64_t start, uint64_t end, uint64_t offset, uint64_t flags,
@@ -209,6 +77,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;
@@ -216,26 +89,16 @@
}
bool BufferMaps::Parse() {
- const char* start_of_line = buffer_;
- do {
- std::string line;
- const char* end_of_line = strchr(start_of_line, '\n');
- if (end_of_line == nullptr) {
- line = start_of_line;
- } else {
- line = std::string(start_of_line, end_of_line - start_of_line);
- end_of_line++;
- }
-
- MapInfo* map_info = InternalParseLine(line.c_str());
- if (map_info == nullptr) {
- return false;
- }
- maps_.push_back(map_info);
-
- start_of_line = end_of_line;
- } while (start_of_line != nullptr && *start_of_line != '\0');
- return true;
+ std::string content(buffer_);
+ return android::procinfo::ReadMapFileContent(
+ &content[0],
+ [&](uint64_t start, uint64_t end, uint16_t flags, uint64_t pgoff, const char* name) {
+ // Mark a device map in /dev/ and not in /dev/ashmem/ specially.
+ if (strncmp(name, "/dev/", 5) == 0 && strncmp(name + 5, "ashmem/", 7) != 0) {
+ flags |= unwindstack::MAPS_FLAGS_DEVICE_MAP;
+ }
+ maps_.push_back(new MapInfo(start, end, pgoff, flags, name));
+ });
}
const std::string RemoteMaps::GetMapsFile() const {
diff --git a/libunwindstack/Unwinder.cpp b/libunwindstack/Unwinder.cpp
index 94edb1c..099cc9e 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.
@@ -210,8 +220,7 @@
in_device_map = true;
} else {
bool finished;
- stepped = elf->Step(rel_pc, step_pc, map_info->elf_offset, regs_, process_memory_.get(),
- &finished);
+ stepped = elf->Step(rel_pc, step_pc, regs_, process_memory_.get(), &finished);
elf->GetLastError(&last_error_);
if (stepped && finished) {
break;
diff --git a/libunwindstack/include/unwindstack/Elf.h b/libunwindstack/include/unwindstack/Elf.h
index 385973e..f4cdbda 100644
--- a/libunwindstack/include/unwindstack/Elf.h
+++ b/libunwindstack/include/unwindstack/Elf.h
@@ -65,8 +65,8 @@
uint64_t GetRelPc(uint64_t pc, const MapInfo* map_info);
- bool Step(uint64_t rel_pc, uint64_t adjusted_rel_pc, uint64_t elf_offset, Regs* regs,
- Memory* process_memory, bool* finished);
+ bool Step(uint64_t rel_pc, uint64_t adjusted_rel_pc, Regs* regs, Memory* process_memory,
+ bool* finished);
ElfInterface* CreateInterfaceFromMemory(Memory* memory);
diff --git a/libunwindstack/include/unwindstack/MapInfo.h b/libunwindstack/include/unwindstack/MapInfo.h
index a57fe68..ac0df41 100644
--- a/libunwindstack/include/unwindstack/MapInfo.h
+++ b/libunwindstack/include/unwindstack/MapInfo.h
@@ -34,6 +34,13 @@
struct MapInfo {
MapInfo() = default;
MapInfo(uint64_t start, uint64_t end) : start(start), end(end) {}
+ MapInfo(uint64_t start, uint64_t end, uint64_t offset, uint64_t flags, const char* name)
+ : start(start),
+ end(end),
+ offset(offset),
+ flags(flags),
+ name(name),
+ load_bias(static_cast<uint64_t>(-1)) {}
MapInfo(uint64_t start, uint64_t end, uint64_t offset, uint64_t flags, const std::string& name)
: start(start),
end(end),
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/ElfTest.cpp b/libunwindstack/tests/ElfTest.cpp
index f9028c4..aecbf6d 100644
--- a/libunwindstack/tests/ElfTest.cpp
+++ b/libunwindstack/tests/ElfTest.cpp
@@ -133,7 +133,7 @@
ASSERT_FALSE(elf.GetFunctionName(0, &name, &func_offset));
bool finished;
- ASSERT_FALSE(elf.Step(0, 0, 0, nullptr, nullptr, &finished));
+ ASSERT_FALSE(elf.Step(0, 0, nullptr, nullptr, &finished));
}
TEST_F(ElfTest, elf32_invalid_machine) {
@@ -330,7 +330,7 @@
elf.FakeSetValid(true);
elf.FakeSetLoadBias(0);
bool finished;
- ASSERT_TRUE(elf.Step(0x1000, 0x1000, 0x2000, ®s, &process_memory, &finished));
+ ASSERT_TRUE(elf.Step(0x3000, 0x1000, ®s, &process_memory, &finished));
EXPECT_FALSE(finished);
EXPECT_EQ(15U, regs.pc());
EXPECT_EQ(13U, regs.sp());
@@ -370,7 +370,7 @@
EXPECT_CALL(*interface, Step(0x1000, 0, ®s, &process_memory, &finished))
.WillOnce(::testing::Return(true));
- ASSERT_TRUE(elf.Step(0x1004, 0x1000, 0x2000, ®s, &process_memory, &finished));
+ ASSERT_TRUE(elf.Step(0x1004, 0x1000, ®s, &process_memory, &finished));
}
TEST_F(ElfTest, step_in_interface_non_zero_load_bias) {
@@ -388,7 +388,7 @@
EXPECT_CALL(*interface, Step(0x7300, 0x4000, ®s, &process_memory, &finished))
.WillOnce(::testing::Return(true));
- ASSERT_TRUE(elf.Step(0x7304, 0x7300, 0x2000, ®s, &process_memory, &finished));
+ ASSERT_TRUE(elf.Step(0x7304, 0x7300, ®s, &process_memory, &finished));
}
TEST_F(ElfTest, get_global_invalid_elf) {
diff --git a/libunwindstack/tests/UnwindOfflineTest.cpp b/libunwindstack/tests/UnwindOfflineTest.cpp
index 8cb640f..285fc9e 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>
@@ -45,6 +46,12 @@
namespace unwindstack {
+static void AddMemory(std::string file_name, MemoryOfflineParts* parts) {
+ MemoryOffline* memory = new MemoryOffline;
+ ASSERT_TRUE(memory->Init(file_name.c_str(), 0));
+ parts->Add(memory);
+}
+
class UnwindOfflineTest : public ::testing::Test {
protected:
void TearDown() override {
@@ -63,9 +70,24 @@
maps_.reset(new BufferMaps(data.c_str()));
ASSERT_TRUE(maps_->Parse());
- std::unique_ptr<MemoryOffline> stack_memory(new MemoryOffline);
- ASSERT_TRUE(stack_memory->Init((dir_ + "stack.data").c_str(), 0));
- process_memory_.reset(stack_memory.release());
+ std::string stack_name(dir_ + "stack.data");
+ struct stat st;
+ if (stat(stack_name.c_str(), &st) == 0 && S_ISREG(st.st_mode)) {
+ std::unique_ptr<MemoryOffline> stack_memory(new MemoryOffline);
+ ASSERT_TRUE(stack_memory->Init((dir_ + "stack.data").c_str(), 0));
+ process_memory_.reset(stack_memory.release());
+ } else {
+ std::unique_ptr<MemoryOfflineParts> stack_memory(new MemoryOfflineParts);
+ for (size_t i = 0;; i++) {
+ stack_name = dir_ + "stack" + std::to_string(i) + ".data";
+ if (stat(stack_name.c_str(), &st) == -1 || !S_ISREG(st.st_mode)) {
+ ASSERT_TRUE(i != 0) << "No stack data files found.";
+ break;
+ }
+ AddMemory(stack_name, stack_memory.get());
+ }
+ process_memory_.reset(stack_memory.release());
+ }
switch (arch) {
case ARCH_ARM: {
@@ -179,7 +201,7 @@
}
TEST_F(UnwindOfflineTest, pc_straddle_arm) {
- Init("straddle_arm/", ARCH_ARM);
+ ASSERT_NO_FATAL_FAILURE(Init("straddle_arm/", ARCH_ARM));
Unwinder unwinder(128, maps_.get(), regs_.get(), process_memory_);
unwinder.Unwind();
@@ -203,7 +225,7 @@
}
TEST_F(UnwindOfflineTest, pc_in_gnu_debugdata_arm) {
- Init("gnu_debugdata_arm/", ARCH_ARM);
+ ASSERT_NO_FATAL_FAILURE(Init("gnu_debugdata_arm/", ARCH_ARM));
Unwinder unwinder(128, maps_.get(), regs_.get(), process_memory_);
unwinder.Unwind();
@@ -223,7 +245,7 @@
}
TEST_F(UnwindOfflineTest, pc_straddle_arm64) {
- Init("straddle_arm64/", ARCH_ARM64);
+ ASSERT_NO_FATAL_FAILURE(Init("straddle_arm64/", ARCH_ARM64));
Unwinder unwinder(128, maps_.get(), regs_.get(), process_memory_);
unwinder.Unwind();
@@ -254,14 +276,8 @@
EXPECT_EQ(0x7fe0d84110U, unwinder.frames()[5].sp);
}
-static void AddMemory(std::string file_name, MemoryOfflineParts* parts) {
- MemoryOffline* memory = new MemoryOffline;
- ASSERT_TRUE(memory->Init(file_name.c_str(), 0));
- parts->Add(memory);
-}
-
TEST_F(UnwindOfflineTest, jit_debug_x86) {
- Init("jit_debug_x86/", ARCH_X86);
+ ASSERT_NO_FATAL_FAILURE(Init("jit_debug_x86/", ARCH_X86));
MemoryOfflineParts* memory = new MemoryOfflineParts;
AddMemory(dir_ + "descriptor.data", memory);
@@ -554,7 +570,7 @@
}
TEST_F(UnwindOfflineTest, jit_debug_arm) {
- Init("jit_debug_arm/", ARCH_ARM);
+ ASSERT_NO_FATAL_FAILURE(Init("jit_debug_arm/", ARCH_ARM));
MemoryOfflineParts* memory = new MemoryOfflineParts;
AddMemory(dir_ + "descriptor.data", memory);
@@ -872,7 +888,7 @@
// fallback to iterating over the cies/fdes and ignore the eh_frame_hdr.
// No .gnu_debugdata section in the elf file, so no symbols.
TEST_F(UnwindOfflineTest, bad_eh_frame_hdr_arm64) {
- Init("bad_eh_frame_hdr_arm64/", ARCH_ARM64);
+ ASSERT_NO_FATAL_FAILURE(Init("bad_eh_frame_hdr_arm64/", ARCH_ARM64));
Unwinder unwinder(128, maps_.get(), regs_.get(), process_memory_);
unwinder.Unwind();
@@ -901,7 +917,7 @@
// The elf has bad eh_frame unwind information for the pcs. If eh_frame
// is used first, the unwind will not match the expected output.
TEST_F(UnwindOfflineTest, debug_frame_first_x86) {
- Init("debug_frame_first_x86/", ARCH_X86);
+ ASSERT_NO_FATAL_FAILURE(Init("debug_frame_first_x86/", ARCH_X86));
Unwinder unwinder(128, maps_.get(), regs_.get(), process_memory_);
unwinder.Unwind();
@@ -929,7 +945,7 @@
// Make sure that a pc that is at the beginning of an fde unwinds correctly.
TEST_F(UnwindOfflineTest, eh_frame_hdr_begin_x86_64) {
- Init("eh_frame_hdr_begin_x86_64/", ARCH_X86_64);
+ ASSERT_NO_FATAL_FAILURE(Init("eh_frame_hdr_begin_x86_64/", ARCH_X86_64));
Unwinder unwinder(128, maps_.get(), regs_.get(), process_memory_);
unwinder.Unwind();
@@ -956,7 +972,7 @@
}
TEST_F(UnwindOfflineTest, art_quick_osr_stub_arm) {
- Init("art_quick_osr_stub_arm/", ARCH_ARM);
+ ASSERT_NO_FATAL_FAILURE(Init("art_quick_osr_stub_arm/", ARCH_ARM));
MemoryOfflineParts* memory = new MemoryOfflineParts;
AddMemory(dir_ + "descriptor.data", memory);
@@ -1070,4 +1086,118 @@
EXPECT_EQ(0xcd4ff960U, unwinder.frames()[24].sp);
}
+TEST_F(UnwindOfflineTest, jit_map_arm) {
+ ASSERT_NO_FATAL_FAILURE(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);
+}
+
+TEST_F(UnwindOfflineTest, offset_arm) {
+ ASSERT_NO_FATAL_FAILURE(Init("offset_arm/", ARCH_ARM));
+
+ Unwinder unwinder(128, maps_.get(), regs_.get(), process_memory_);
+ unwinder.Unwind();
+
+ std::string frame_info(DumpFrames(unwinder));
+ ASSERT_EQ(19U, unwinder.NumFrames()) << "Unwind:\n" << frame_info;
+ EXPECT_EQ(
+ " #00 pc 0032bfa0 (offset 0x42000) libunwindstack_test (SignalInnerFunction+40)\n"
+ " #01 pc 0032bfeb (offset 0x42000) libunwindstack_test (SignalMiddleFunction+2)\n"
+ " #02 pc 0032bff3 (offset 0x42000) libunwindstack_test (SignalOuterFunction+2)\n"
+ " #03 pc 0032fed3 (offset 0x42000) libunwindstack_test "
+ "(_ZN11unwindstackL19SignalCallerHandlerEiP7siginfoPv+26)\n"
+ " #04 pc 00026528 (offset 0x25000) libc.so\n"
+ " #05 pc 00000000 <unknown>\n"
+ " #06 pc 0032c2d9 (offset 0x42000) libunwindstack_test (InnerFunction+736)\n"
+ " #07 pc 0032cc4f (offset 0x42000) libunwindstack_test (MiddleFunction+42)\n"
+ " #08 pc 0032cc81 (offset 0x42000) libunwindstack_test (OuterFunction+42)\n"
+ " #09 pc 0032e547 (offset 0x42000) libunwindstack_test "
+ "(_ZN11unwindstackL19RemoteThroughSignalEij+270)\n"
+ " #10 pc 0032ed99 (offset 0x42000) libunwindstack_test "
+ "(_ZN11unwindstack55UnwindTest_remote_through_signal_with_invalid_func_Test8TestBodyEv+16)\n"
+ " #11 pc 00354453 (offset 0x42000) libunwindstack_test (_ZN7testing4Test3RunEv+154)\n"
+ " #12 pc 00354de7 (offset 0x42000) libunwindstack_test (_ZN7testing8TestInfo3RunEv+194)\n"
+ " #13 pc 00355105 (offset 0x42000) libunwindstack_test (_ZN7testing8TestCase3RunEv+180)\n"
+ " #14 pc 0035a215 (offset 0x42000) libunwindstack_test "
+ "(_ZN7testing8internal12UnitTestImpl11RunAllTestsEv+664)\n"
+ " #15 pc 00359f4f (offset 0x42000) libunwindstack_test (_ZN7testing8UnitTest3RunEv+110)\n"
+ " #16 pc 0034d3db (offset 0x42000) libunwindstack_test (main+38)\n"
+ " #17 pc 00092c0d (offset 0x25000) libc.so (__libc_init+48)\n"
+ " #18 pc 0004202f (offset 0x42000) libunwindstack_test (_start_main+38)\n",
+ frame_info);
+
+ EXPECT_EQ(0x2e55fa0U, unwinder.frames()[0].pc);
+ EXPECT_EQ(0xf43d2cccU, unwinder.frames()[0].sp);
+ EXPECT_EQ(0x2e55febU, unwinder.frames()[1].pc);
+ EXPECT_EQ(0xf43d2ce0U, unwinder.frames()[1].sp);
+ EXPECT_EQ(0x2e55ff3U, unwinder.frames()[2].pc);
+ EXPECT_EQ(0xf43d2ce8U, unwinder.frames()[2].sp);
+ EXPECT_EQ(0x2e59ed3U, unwinder.frames()[3].pc);
+ EXPECT_EQ(0xf43d2cf0U, unwinder.frames()[3].sp);
+ EXPECT_EQ(0xf4136528U, unwinder.frames()[4].pc);
+ EXPECT_EQ(0xf43d2d10U, unwinder.frames()[4].sp);
+ EXPECT_EQ(0U, unwinder.frames()[5].pc);
+ EXPECT_EQ(0xffcc0ee0U, unwinder.frames()[5].sp);
+ EXPECT_EQ(0x2e562d9U, unwinder.frames()[6].pc);
+ EXPECT_EQ(0xffcc0ee0U, unwinder.frames()[6].sp);
+ EXPECT_EQ(0x2e56c4fU, unwinder.frames()[7].pc);
+ EXPECT_EQ(0xffcc1060U, unwinder.frames()[7].sp);
+ EXPECT_EQ(0x2e56c81U, unwinder.frames()[8].pc);
+ EXPECT_EQ(0xffcc1078U, unwinder.frames()[8].sp);
+ EXPECT_EQ(0x2e58547U, unwinder.frames()[9].pc);
+ EXPECT_EQ(0xffcc1090U, unwinder.frames()[9].sp);
+ EXPECT_EQ(0x2e58d99U, unwinder.frames()[10].pc);
+ EXPECT_EQ(0xffcc1438U, unwinder.frames()[10].sp);
+ EXPECT_EQ(0x2e7e453U, unwinder.frames()[11].pc);
+ EXPECT_EQ(0xffcc1448U, unwinder.frames()[11].sp);
+ EXPECT_EQ(0x2e7ede7U, unwinder.frames()[12].pc);
+ EXPECT_EQ(0xffcc1458U, unwinder.frames()[12].sp);
+ EXPECT_EQ(0x2e7f105U, unwinder.frames()[13].pc);
+ EXPECT_EQ(0xffcc1490U, unwinder.frames()[13].sp);
+ EXPECT_EQ(0x2e84215U, unwinder.frames()[14].pc);
+ EXPECT_EQ(0xffcc14c0U, unwinder.frames()[14].sp);
+ EXPECT_EQ(0x2e83f4fU, unwinder.frames()[15].pc);
+ EXPECT_EQ(0xffcc1510U, unwinder.frames()[15].sp);
+ EXPECT_EQ(0x2e773dbU, unwinder.frames()[16].pc);
+ EXPECT_EQ(0xffcc1528U, unwinder.frames()[16].sp);
+ EXPECT_EQ(0xf41a2c0dU, unwinder.frames()[17].pc);
+ EXPECT_EQ(0xffcc1540U, unwinder.frames()[17].sp);
+ EXPECT_EQ(0x2b6c02fU, unwinder.frames()[18].pc);
+ EXPECT_EQ(0xffcc1558U, unwinder.frames()[18].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/libunwindstack/tests/files/offline/offset_arm/libc.so b/libunwindstack/tests/files/offline/offset_arm/libc.so
new file mode 100644
index 0000000..9f5c8ca
--- /dev/null
+++ b/libunwindstack/tests/files/offline/offset_arm/libc.so
Binary files differ
diff --git a/libunwindstack/tests/files/offline/offset_arm/libunwindstack_test b/libunwindstack/tests/files/offline/offset_arm/libunwindstack_test
new file mode 100644
index 0000000..7a30bfa
--- /dev/null
+++ b/libunwindstack/tests/files/offline/offset_arm/libunwindstack_test
Binary files differ
diff --git a/libunwindstack/tests/files/offline/offset_arm/maps.txt b/libunwindstack/tests/files/offline/offset_arm/maps.txt
new file mode 100644
index 0000000..6224464
--- /dev/null
+++ b/libunwindstack/tests/files/offline/offset_arm/maps.txt
@@ -0,0 +1,2 @@
+2b6c000-2e92000 r-xp 42000 00:00 0 libunwindstack_test
+f4135000-f41a9000 r-xp 25000 00:00 0 libc.so
diff --git a/libunwindstack/tests/files/offline/offset_arm/regs.txt b/libunwindstack/tests/files/offline/offset_arm/regs.txt
new file mode 100644
index 0000000..1f4ac8f
--- /dev/null
+++ b/libunwindstack/tests/files/offline/offset_arm/regs.txt
@@ -0,0 +1,16 @@
+r0: 5
+r1: 5
+r2: 4
+r3: 1
+r4: 73804b6b
+r5: f3c9c000
+r6: 2ea09ac
+r7: 10624dd3
+r8: f41b5d8c
+r9: f3c9c000
+r10: 6f17
+r11: f3c94048
+ip: 2ea0807
+sp: f43d2ccc
+lr: 2e55fef
+pc: 2e55fa0
diff --git a/libunwindstack/tests/files/offline/offset_arm/stack0.data b/libunwindstack/tests/files/offline/offset_arm/stack0.data
new file mode 100644
index 0000000..23a9874
--- /dev/null
+++ b/libunwindstack/tests/files/offline/offset_arm/stack0.data
Binary files differ
diff --git a/libunwindstack/tests/files/offline/offset_arm/stack1.data b/libunwindstack/tests/files/offline/offset_arm/stack1.data
new file mode 100644
index 0000000..49bdd1e
--- /dev/null
+++ b/libunwindstack/tests/files/offline/offset_arm/stack1.data
Binary files differ
diff --git a/libunwindstack/tools/unwind_for_offline.cpp b/libunwindstack/tools/unwind_for_offline.cpp
index 74868d4..589731d 100644
--- a/libunwindstack/tools/unwind_for_offline.cpp
+++ b/libunwindstack/tools/unwind_for_offline.cpp
@@ -30,6 +30,7 @@
#include <memory>
#include <string>
#include <unordered_map>
+#include <utility>
#include <vector>
#include <unwindstack/Elf.h>
@@ -78,30 +79,44 @@
return true;
}
-bool SaveStack(pid_t pid, uint64_t sp_start, uint64_t sp_end) {
- std::unique_ptr<FILE, decltype(&fclose)> fp(fopen("stack.data", "w+"), &fclose);
- if (fp == nullptr) {
- printf("Failed to create stack.data.\n");
- return false;
- }
+bool SaveStack(pid_t pid, const std::vector<std::pair<uint64_t, uint64_t>>& stacks) {
+ for (size_t i = 0; i < stacks.size(); i++) {
+ std::string file_name;
+ if (stacks.size() != 1) {
+ file_name = "stack" + std::to_string(i) + ".data";
+ } else {
+ file_name = "stack.data";
+ }
- size_t bytes = fwrite(&sp_start, 1, sizeof(sp_start), fp.get());
- if (bytes != sizeof(sp_start)) {
- perror("Failed to write all data.");
- return false;
- }
+ // Do this first, so if it fails, we don't create the file.
+ uint64_t sp_start = stacks[i].first;
+ uint64_t sp_end = stacks[i].second;
+ std::vector<uint8_t> buffer(sp_end - sp_start);
+ auto process_memory = unwindstack::Memory::CreateProcessMemory(pid);
+ if (!process_memory->Read(sp_start, buffer.data(), buffer.size())) {
+ printf("Unable to read stack data.\n");
+ return false;
+ }
- std::vector<uint8_t> buffer(sp_end - sp_start);
- auto process_memory = unwindstack::Memory::CreateProcessMemory(pid);
- if (!process_memory->Read(sp_start, buffer.data(), buffer.size())) {
- printf("Unable to read stack data.\n");
- return false;
- }
+ printf("Saving the stack 0x%" PRIx64 "-0x%" PRIx64 "\n", sp_start, sp_end);
- bytes = fwrite(buffer.data(), 1, buffer.size(), fp.get());
- if (bytes != buffer.size()) {
- printf("Failed to write all stack data: stack size %zu, written %zu\n", buffer.size(), bytes);
- return 1;
+ std::unique_ptr<FILE, decltype(&fclose)> fp(fopen(file_name.c_str(), "w+"), &fclose);
+ if (fp == nullptr) {
+ printf("Failed to create stack.data.\n");
+ return false;
+ }
+
+ size_t bytes = fwrite(&sp_start, 1, sizeof(sp_start), fp.get());
+ if (bytes != sizeof(sp_start)) {
+ perror("Failed to write all data.");
+ return false;
+ }
+
+ bytes = fwrite(buffer.data(), 1, buffer.size(), fp.get());
+ if (bytes != buffer.size()) {
+ printf("Failed to write all stack data: stack size %zu, written %zu\n", buffer.size(), bytes);
+ return false;
+ }
}
return true;
@@ -110,17 +125,11 @@
bool CreateElfFromMemory(std::shared_ptr<unwindstack::Memory>& memory, map_info_t* info) {
std::string cur_name;
if (info->name.empty()) {
- cur_name = android::base::StringPrintf("anonymous:%" PRIx64, info->start);
+ cur_name = android::base::StringPrintf("anonymous_%" PRIx64, info->start);
} else {
- cur_name = basename(info->name.c_str());
- cur_name = android::base::StringPrintf("%s:%" PRIx64, basename(info->name.c_str()), info->start);
+ cur_name = android::base::StringPrintf("%s_%" PRIx64, basename(info->name.c_str()), info->start);
}
- std::unique_ptr<FILE, decltype(&fclose)> output(fopen(cur_name.c_str(), "w+"), &fclose);
- if (output == nullptr) {
- printf("Cannot create %s\n", cur_name.c_str());
- return false;
- }
std::vector<uint8_t> buffer(info->end - info->start);
// If this is a mapped in file, it might not be possible to read the entire
// map, so read all that is readable.
@@ -129,6 +138,13 @@
printf("Cannot read data from address %" PRIx64 " length %zu\n", info->start, buffer.size());
return false;
}
+
+ std::unique_ptr<FILE, decltype(&fclose)> output(fopen(cur_name.c_str(), "w+"), &fclose);
+ if (output == nullptr) {
+ printf("Cannot create %s\n", cur_name.c_str());
+ return false;
+ }
+
size_t bytes_written = fwrite(buffer.data(), 1, bytes, output.get());
if (bytes_written != bytes) {
printf("Failed to write all data to file: bytes read %zu, written %zu\n", bytes, bytes_written);
@@ -198,9 +214,21 @@
unwinder.Unwind();
std::unordered_map<uint64_t, map_info_t> maps_by_start;
- uint64_t last_sp;
+ std::vector<std::pair<uint64_t, uint64_t>> stacks;
+ uint64_t sp_map_start = 0;
+ unwindstack::MapInfo* map_info = maps.Find(sp);
+ if (map_info != nullptr) {
+ stacks.emplace_back(std::make_pair(sp, map_info->end));
+ sp_map_start = map_info->start;
+ }
+
for (auto frame : unwinder.frames()) {
- last_sp = frame.sp;
+ map_info = maps.Find(frame.sp);
+ if (map_info != nullptr && sp_map_start != map_info->start) {
+ stacks.emplace_back(std::make_pair(frame.sp, map_info->end));
+ sp_map_start = map_info->start;
+ }
+
if (maps_by_start.count(frame.map_start) == 0) {
auto info = &maps_by_start[frame.map_start];
info->start = frame.map_start;
@@ -211,7 +239,12 @@
// Try to create the elf from memory, this will handle cases where
// the data only exists in memory such as vdso data on x86.
if (!CreateElfFromMemory(process_memory, info)) {
- return 1;
+ printf("Ignoring map ");
+ if (!info->name.empty()) {
+ printf("%s\n", info->name.c_str());
+ } else {
+ printf("anonymous:%" PRIx64 "\n", info->start);
+ }
}
}
}
@@ -221,7 +254,7 @@
printf("%s\n", unwinder.FormatFrame(i).c_str());
}
- if (!SaveStack(pid, sp, last_sp)) {
+ if (!SaveStack(pid, stacks)) {
return 1;
}
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/SharedBuffer.h b/libutils/SharedBuffer.h
index 48358cd..81cadff 100644
--- a/libutils/SharedBuffer.h
+++ b/libutils/SharedBuffer.h
@@ -139,7 +139,7 @@
return (mRefs.load(std::memory_order_acquire) == 1);
}
-}; // namespace android
+} // namespace android
// ---------------------------------------------------------------------------
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/libutils/include/utils/AndroidThreads.h b/libutils/include/utils/AndroidThreads.h
index 4c2dd49..dab888d 100644
--- a/libutils/include/utils/AndroidThreads.h
+++ b/libutils/include/utils/AndroidThreads.h
@@ -118,7 +118,7 @@
}
// ----------------------------------------------------------------------------
-}; // namespace android
+} // namespace android
#endif // __cplusplus
// ----------------------------------------------------------------------------
diff --git a/libutils/include/utils/CallStack.h b/libutils/include/utils/CallStack.h
index 27e89f4..9622142 100644
--- a/libutils/include/utils/CallStack.h
+++ b/libutils/include/utils/CallStack.h
@@ -67,6 +67,6 @@
Vector<String8> mFrameLines;
};
-}; // namespace android
+} // namespace android
#endif // ANDROID_CALLSTACK_H
diff --git a/libutils/include/utils/Condition.h b/libutils/include/utils/Condition.h
index 9bf82eb..c8da67c 100644
--- a/libutils/include/utils/Condition.h
+++ b/libutils/include/utils/Condition.h
@@ -159,7 +159,7 @@
#endif // !defined(_WIN32)
// ---------------------------------------------------------------------------
-}; // namespace android
+} // namespace android
// ---------------------------------------------------------------------------
#endif // _LIBS_UTILS_CONDITON_H
diff --git a/libutils/include/utils/Debug.h b/libutils/include/utils/Debug.h
index 4cbb462..96bd70e 100644
--- a/libutils/include/utils/Debug.h
+++ b/libutils/include/utils/Debug.h
@@ -35,6 +35,6 @@
CompileTimeAssert<( _exp )>();
// ---------------------------------------------------------------------------
-}; // namespace android
+} // namespace android
#endif // ANDROID_UTILS_DEBUG_H
diff --git a/libutils/include/utils/Errors.h b/libutils/include/utils/Errors.h
index 16e1fa2..7093a20 100644
--- a/libutils/include/utils/Errors.h
+++ b/libutils/include/utils/Errors.h
@@ -81,8 +81,8 @@
# define NO_ERROR 0L
#endif
-}; // namespace android
-
+} // namespace android
+
// ---------------------------------------------------------------------------
#endif // ANDROID_ERRORS_H
diff --git a/libutils/include/utils/FileMap.h b/libutils/include/utils/FileMap.h
index 7d372e1..8d402a3 100644
--- a/libutils/include/utils/FileMap.h
+++ b/libutils/include/utils/FileMap.h
@@ -124,6 +124,6 @@
static long mPageSize;
};
-}; // namespace android
+} // namespace android
#endif // __LIBS_FILE_MAP_H
diff --git a/libutils/include/utils/Flattenable.h b/libutils/include/utils/Flattenable.h
index 675e211..0a19019 100644
--- a/libutils/include/utils/Flattenable.h
+++ b/libutils/include/utils/Flattenable.h
@@ -198,8 +198,6 @@
}
};
-
-}; // namespace android
-
+} // namespace android
#endif /* ANDROID_UTILS_FLATTENABLE_H */
diff --git a/libutils/include/utils/Functor.h b/libutils/include/utils/Functor.h
index 3182a9c..c0c8d57 100644
--- a/libutils/include/utils/Functor.h
+++ b/libutils/include/utils/Functor.h
@@ -32,6 +32,6 @@
virtual status_t operator ()(int /*what*/, void* /*data*/) { return NO_ERROR; }
};
-}; // namespace android
+} // namespace android
#endif // ANDROID_FUNCTOR_H
diff --git a/libutils/include/utils/KeyedVector.h b/libutils/include/utils/KeyedVector.h
index 03bfe27..7bda99b 100644
--- a/libutils/include/utils/KeyedVector.h
+++ b/libutils/include/utils/KeyedVector.h
@@ -211,7 +211,7 @@
return i >= 0 ? KeyedVector<KEY,VALUE>::valueAt(i) : mDefault;
}
-}; // namespace android
+} // namespace android
// ---------------------------------------------------------------------------
diff --git a/libutils/include/utils/LightRefBase.h b/libutils/include/utils/LightRefBase.h
index 65257ed..e488e60 100644
--- a/libutils/include/utils/LightRefBase.h
+++ b/libutils/include/utils/LightRefBase.h
@@ -69,4 +69,4 @@
virtual ~VirtualLightRefBase() = default;
};
-}; // namespace android
+} // namespace android
diff --git a/libutils/include/utils/List.h b/libutils/include/utils/List.h
index daca016..25b56fd 100644
--- a/libutils/include/utils/List.h
+++ b/libutils/include/utils/List.h
@@ -329,6 +329,6 @@
return *this;
}
-}; // namespace android
+} // namespace android
#endif // _LIBS_UTILS_LIST_H
diff --git a/libutils/include/utils/Mutex.h b/libutils/include/utils/Mutex.h
index af6076c..1228df4 100644
--- a/libutils/include/utils/Mutex.h
+++ b/libutils/include/utils/Mutex.h
@@ -212,7 +212,7 @@
typedef Mutex::Autolock AutoMutex;
// ---------------------------------------------------------------------------
-}; // namespace android
+} // namespace android
// ---------------------------------------------------------------------------
#endif // _LIBS_UTILS_MUTEX_H
diff --git a/libutils/include/utils/Printer.h b/libutils/include/utils/Printer.h
index bb66287..a6f6928 100644
--- a/libutils/include/utils/Printer.h
+++ b/libutils/include/utils/Printer.h
@@ -114,6 +114,6 @@
const char* mPrefix;
};
-}; // namespace android
+} // namespace android
#endif // ANDROID_PRINTER_H
diff --git a/libutils/include/utils/ProcessCallStack.h b/libutils/include/utils/ProcessCallStack.h
index 32458b8..b5f2edc 100644
--- a/libutils/include/utils/ProcessCallStack.h
+++ b/libutils/include/utils/ProcessCallStack.h
@@ -74,6 +74,6 @@
struct tm mTimeUpdated;
};
-}; // namespace android
+} // namespace android
#endif // ANDROID_PROCESS_CALLSTACK_H
diff --git a/libutils/include/utils/RWLock.h b/libutils/include/utils/RWLock.h
index d5b81d3..7d43e69 100644
--- a/libutils/include/utils/RWLock.h
+++ b/libutils/include/utils/RWLock.h
@@ -120,7 +120,7 @@
#endif // !defined(_WIN32)
// ---------------------------------------------------------------------------
-}; // namespace android
+} // namespace android
// ---------------------------------------------------------------------------
#endif // _LIBS_UTILS_RWLOCK_H
diff --git a/libutils/include/utils/RefBase.h b/libutils/include/utils/RefBase.h
index 223b666..e817ee4 100644
--- a/libutils/include/utils/RefBase.h
+++ b/libutils/include/utils/RefBase.h
@@ -683,7 +683,7 @@
ReferenceMover::move_references(d, s, n);
}
-}; // namespace android
+} // namespace android
// ---------------------------------------------------------------------------
diff --git a/libutils/include/utils/Singleton.h b/libutils/include/utils/Singleton.h
index bc47a5c..2dd5a47 100644
--- a/libutils/include/utils/Singleton.h
+++ b/libutils/include/utils/Singleton.h
@@ -95,7 +95,7 @@
// ---------------------------------------------------------------------------
-}; // namespace android
+} // namespace android
#endif // ANDROID_UTILS_SINGLETON_H
diff --git a/libutils/include/utils/SortedVector.h b/libutils/include/utils/SortedVector.h
index 47c1376..394db12 100644
--- a/libutils/include/utils/SortedVector.h
+++ b/libutils/include/utils/SortedVector.h
@@ -288,8 +288,7 @@
return compare_type( *reinterpret_cast<const TYPE*>(lhs), *reinterpret_cast<const TYPE*>(rhs) );
}
-}; // namespace android
-
+} // namespace android
// ---------------------------------------------------------------------------
diff --git a/libutils/include/utils/StopWatch.h b/libutils/include/utils/StopWatch.h
index 76d78d0..9b14ac8 100644
--- a/libutils/include/utils/StopWatch.h
+++ b/libutils/include/utils/StopWatch.h
@@ -52,9 +52,7 @@
int mNumLaps;
};
-
-}; // namespace android
-
+} // namespace android
// ---------------------------------------------------------------------------
diff --git a/libutils/include/utils/String16.h b/libutils/include/utils/String16.h
index 5f0ce06..afbc2ed 100644
--- a/libutils/include/utils/String16.h
+++ b/libutils/include/utils/String16.h
@@ -243,7 +243,7 @@
return mString;
}
-}; // namespace android
+} // namespace android
// ---------------------------------------------------------------------------
diff --git a/libutils/include/utils/StrongPointer.h b/libutils/include/utils/StrongPointer.h
index ae6d9c8..9cd278f1 100644
--- a/libutils/include/utils/StrongPointer.h
+++ b/libutils/include/utils/StrongPointer.h
@@ -239,7 +239,7 @@
m_ptr = ptr;
}
-}; // namespace android
+} // namespace android
// ---------------------------------------------------------------------------
diff --git a/libutils/include/utils/SystemClock.h b/libutils/include/utils/SystemClock.h
index 01db340..f816fba 100644
--- a/libutils/include/utils/SystemClock.h
+++ b/libutils/include/utils/SystemClock.h
@@ -26,7 +26,7 @@
int64_t elapsedRealtime();
int64_t elapsedRealtimeNano();
-}; // namespace android
+} // namespace android
#endif // ANDROID_UTILS_SYSTEMCLOCK_H
diff --git a/libutils/include/utils/Thread.h b/libutils/include/utils/Thread.h
index 598298d..3525138 100644
--- a/libutils/include/utils/Thread.h
+++ b/libutils/include/utils/Thread.h
@@ -110,8 +110,7 @@
#endif
};
-
-}; // namespace android
+} // namespace android
// ---------------------------------------------------------------------------
#endif // _LIBS_UTILS_THREAD_H
diff --git a/libutils/include/utils/ThreadDefs.h b/libutils/include/utils/ThreadDefs.h
index ae091e4..8eb3d1c 100644
--- a/libutils/include/utils/ThreadDefs.h
+++ b/libutils/include/utils/ThreadDefs.h
@@ -66,9 +66,8 @@
};
// ---------------------------------------------------------------------------
-}; // namespace android
+} // namespace android
#endif // __cplusplus
// ---------------------------------------------------------------------------
-
#endif // _LIBS_UTILS_THREAD_DEFS_H
diff --git a/libutils/include/utils/Trace.h b/libutils/include/utils/Trace.h
index 5e9229c..4b9c91e 100644
--- a/libutils/include/utils/Trace.h
+++ b/libutils/include/utils/Trace.h
@@ -49,7 +49,7 @@
uint64_t mTag;
};
-}; // namespace android
+} // namespace android
#else // !__ANDROID__
diff --git a/libutils/include/utils/TypeHelpers.h b/libutils/include/utils/TypeHelpers.h
index 28fbca5..1554f52 100644
--- a/libutils/include/utils/TypeHelpers.h
+++ b/libutils/include/utils/TypeHelpers.h
@@ -329,7 +329,7 @@
return hash_type(uintptr_t(value));
}
-}; // namespace android
+} // namespace android
// ---------------------------------------------------------------------------
diff --git a/libutils/include/utils/Vector.h b/libutils/include/utils/Vector.h
index a1a0234..ddf71de 100644
--- a/libutils/include/utils/Vector.h
+++ b/libutils/include/utils/Vector.h
@@ -425,8 +425,7 @@
move_backward_type( reinterpret_cast<TYPE*>(dest), reinterpret_cast<const TYPE*>(from), num );
}
-}; // namespace android
-
+} // namespace android
// ---------------------------------------------------------------------------
diff --git a/libutils/include/utils/VectorImpl.h b/libutils/include/utils/VectorImpl.h
index 4dd91fd..55d5d98 100644
--- a/libutils/include/utils/VectorImpl.h
+++ b/libutils/include/utils/VectorImpl.h
@@ -175,8 +175,7 @@
ssize_t replaceAt(const void* item, size_t index);
};
-}; // namespace android
-
+} // namespace android
// ---------------------------------------------------------------------------
diff --git a/libutils/include/utils/misc.h b/libutils/include/utils/misc.h
index af5ea02..32615b3 100644
--- a/libutils/include/utils/misc.h
+++ b/libutils/include/utils/misc.h
@@ -35,6 +35,6 @@
void add_sysprop_change_callback(sysprop_change_callback cb, int priority);
void report_sysprop_change();
-}; // namespace android
+} // namespace android
#endif // _LIBS_UTILS_MISC_H
diff --git a/libziparchive/Android.bp b/libziparchive/Android.bp
index 075fb86..6c06618 100644
--- a/libziparchive/Android.bp
+++ b/libziparchive/Android.bp
@@ -61,6 +61,7 @@
vndk: {
enabled: true,
},
+ double_loadable: true,
defaults: [
"libziparchive_defaults",
@@ -92,6 +93,10 @@
host_supported: true,
defaults: ["libziparchive_flags"],
+ data: [
+ "testdata/**/*",
+ ],
+
srcs: [
"entry_name_utils_test.cc",
"zip_archive_test.cc",
diff --git a/libziparchive/zip_archive_test.cc b/libziparchive/zip_archive_test.cc
index ff73eb2..23dd5dc 100644
--- a/libziparchive/zip_archive_test.cc
+++ b/libziparchive/zip_archive_test.cc
@@ -34,7 +34,7 @@
#include <ziparchive/zip_archive.h>
#include <ziparchive/zip_archive_stream_entry.h>
-static std::string test_data_dir;
+static std::string test_data_dir = android::base::GetExecutableDirectory() + "/testdata";
static const std::string kMissingZip = "missing.zip";
static const std::string kValidZip = "valid.zip";
@@ -778,41 +778,3 @@
ASSERT_EQ(0u, writer.GetOutput().size());
}
}
-
-int main(int argc, char** argv) {
- ::testing::InitGoogleTest(&argc, argv);
-
- static struct option options[] = {{"test_data_dir", required_argument, nullptr, 't'},
- {nullptr, 0, nullptr, 0}};
-
- while (true) {
- int option_index;
- const int c = getopt_long_only(argc, argv, "", options, &option_index);
- if (c == -1) {
- break;
- }
-
- if (c == 't') {
- test_data_dir = optarg;
- }
- }
-
- if (test_data_dir.size() == 0) {
- printf("Test data flag (--test_data_dir) required\n\n");
- return -1;
- }
-
- if (test_data_dir[0] != '/') {
- std::vector<char> cwd_buffer(1024);
- const char* cwd = getcwd(cwd_buffer.data(), cwd_buffer.size() - 1);
- if (cwd == nullptr) {
- printf("Cannot get current working directory, use an absolute path instead, was %s\n\n",
- test_data_dir.c_str());
- return -2;
- }
- test_data_dir = '/' + test_data_dir;
- test_data_dir = cwd + test_data_dir;
- }
-
- return RUN_ALL_TESTS();
-}
diff --git a/llkd/Android.bp b/llkd/Android.bp
new file mode 100644
index 0000000..a6edd26
--- /dev/null
+++ b/llkd/Android.bp
@@ -0,0 +1,42 @@
+cc_library_headers {
+ name: "llkd_headers",
+
+ export_include_dirs: ["include"],
+}
+
+cc_library_static {
+ name: "libllkd",
+
+ srcs: [
+ "libllkd.cpp",
+ ],
+
+ shared_libs: [
+ "libbase",
+ "libcutils",
+ "liblog",
+ ],
+
+ export_include_dirs: ["include"],
+
+ cflags: ["-Werror"],
+}
+
+cc_binary {
+ name: "llkd",
+
+ srcs: [
+ "llkd.cpp",
+ ],
+ shared_libs: [
+ "libbase",
+ "libcutils",
+ "liblog",
+ ],
+ static_libs: [
+ "libllkd",
+ ],
+ cflags: ["-Werror"],
+
+ init_rc: ["llkd.rc"],
+}
diff --git a/llkd/OWNERS b/llkd/OWNERS
new file mode 100644
index 0000000..b6af537
--- /dev/null
+++ b/llkd/OWNERS
@@ -0,0 +1,2 @@
+salyzyn@google.com
+surenb@google.com
diff --git a/llkd/README.md b/llkd/README.md
new file mode 100644
index 0000000..b2ba2a2
--- /dev/null
+++ b/llkd/README.md
@@ -0,0 +1,117 @@
+Android Live-LocK Daemon
+========================
+
+Introduction
+------------
+
+Android Live-LocK Daemon (llkd) is used to catch kernel deadlocks and mitigate.
+
+Code is structured to allow integration into another service as either as part
+of the main loop, or spun off as a thread should that be necessary. A default
+standalone implementation is provided by llkd component.
+
+The 'C' interface from libllkd component is thus:
+
+ #include "llkd.h"
+ bool llkInit(const char* threadname) /* return true if enabled */
+ unsigned llkCheckMillseconds(void) /* ms to sleep for next check */
+
+If a threadname is provided, a thread will be automatically spawned, otherwise
+caller must call llkCheckMilliseconds in its main loop. Function will return
+the period of time before the next expected call to this handler.
+
+Operations
+----------
+
+If a thread is in D or Z state with no forward progress for longer than
+ro.llk.timeout_ms, or ro.llk.[D|Z].timeout_ms, kill the process or parent
+process respectively. If another scan shows the same process continues to
+exist, then have a confirmed live-lock condition and need to panic. Panic
+the kernel in a manner to provide the greatest bugreporting details as to the
+condition. Add a alarm self watchdog should llkd ever get locked up that is
+double the expected time to flow through the mainloop. Sampling is every
+ro.llk_sample_ms.
+
+Default will not monitor init, or [kthreadd] and all that [kthreadd] spawns.
+This reduces the effectiveness of llkd by limiting its coverage. If there is
+value in covering [kthreadd] spawned threads, the requirement will be that
+the drivers not remain in a persistent 'D' state, or that they have mechanisms
+to recover the thread should it be killed externally (this is good driver
+coding hygiene, a common request to add such to publicly reviewed kernel.org
+maintained drivers). For instance use wait_event_interruptible() instead of
+wait_event(). The blacklists can be adjusted accordingly if these
+conditions are met to cover kernel components.
+
+An accompanying gTest set have been added, and will setup a persistent D or Z
+process, with and without forward progress, but not in a live-lock state
+because that would require a buggy kernel, or a module or kernel modification
+to stimulate. The test will check that llkd will mitigate first by killing
+the appropriate process. D state is setup by vfork() waiting for exec() in
+child process. Z state is setup by fork() and an un-waited for child process.
+Should be noted that both of these conditions should never happen on Android
+on purpose, and llkd effectively sweeps up processes that create these
+conditions. If the test can, it will reconfigure llkd to expedite the test
+duration by adjusting the ro.llk.* Android properties. Tests run the D state
+with some scheduling progress to ensure that ABA checking prevents false
+triggers. If 100% reliable ABA on platform, then ro.llk.killtest can be
+set to false; however this will result in some of the unit tests to panic
+kernel instead of deal with more graceful kill operation.
+
+Android Properties
+------------------
+
+Android Properties llkd respond to (<prop>_ms parms are in milliseconds):
+
+#### ro.config.low_ram
+default false, if true do not sysrq t (dump all threads).
+
+#### ro.llk.enable
+default false, allow live-lock daemon to be enabled.
+
+#### llk.enable
+default ro.llk.enable, and evaluated for eng.
+
+#### ro.khungtask.enable
+default false, allow [khungtask] daemon to be enabled.
+
+#### khungtask.enable
+default ro.khungtask.enable and evaluated for eng.
+
+#### ro.llk.mlockall
+default false, enable call to mlockall().
+
+#### ro.khungtask.timeout
+default value 12 minutes, [khungtask] maximum timelimit.
+
+#### ro.llk.timeout_ms
+default 10 minutes, D or Z maximum timelimit, double this value and it sets
+the alarm watchdog for llkd.
+
+#### ro.llk.D.timeout_ms
+default ro.llk.timeout_ms, D maximum timelimit.
+
+#### ro.llk.Z.timeout_ms
+default ro.llk.timeout_ms, Z maximum timelimit.
+
+#### ro.llk.check_ms
+default 2 minutes samples of threads for D or Z.
+
+#### ro.llk.blacklist.process
+default 0,1,2 (kernel, init and [kthreadd]) plus process names
+init,[kthreadd],[khungtaskd],lmkd,lmkd.llkd,llkd,watchdogd,
+[watchdogd],[watchdogd/0],...,[watchdogd/<get_nprocs-1>].
+
+#### ro.llk.blacklist.parent
+default 0,2 (kernel and [kthreadd]).
+
+#### ro.llk.blacklist.uid
+default <empty>, comma separated list of uid numbers or names.
+
+Architectural Concerns
+----------------------
+
+- Create kernel module and associated gTest to actually test panic.
+- Create gTest to test out blacklist (ro.llk.blacklist.<properties> generally
+ not be inputs). Could require more test-only interfaces to libllkd.
+- Speed up gTest using something else than ro.llk.<properties>, which should
+ not be inputs.
diff --git a/llkd/include/llkd.h b/llkd/include/llkd.h
new file mode 100644
index 0000000..e3ae4bb
--- /dev/null
+++ b/llkd/include/llkd.h
@@ -0,0 +1,80 @@
+/*
+ * 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.
+ */
+
+#ifndef _LLKD_H_
+#define _LLKD_H_
+
+#ifndef LOG_TAG
+#define LOG_TAG "livelock"
+#endif
+
+#include <stdbool.h>
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+
+bool llkInit(const char* threadname); /* threadname NULL, not spawned */
+unsigned llkCheckMilliseconds(void);
+
+/* clang-format off */
+#define LLK_ENABLE_WRITEABLE_PROPERTY "llk.enable"
+#define LLK_ENABLE_PROPERTY "ro." LLK_ENABLE_WRITEABLE_PROPERTY
+#define LLK_ENABLE_DEFAULT false /* "eng" and userdebug true */
+#define KHT_ENABLE_WRITEABLE_PROPERTY "khungtask.enable"
+#define KHT_ENABLE_PROPERTY "ro." KHT_ENABLE_WRITEABLE_PROPERTY
+#define LLK_MLOCKALL_PROPERTY "ro.llk.mlockall"
+#define LLK_MLOCKALL_DEFAULT true
+#define LLK_KILLTEST_PROPERTY "ro.llk.killtest"
+#define LLK_KILLTEST_DEFAULT true
+#define LLK_TIMEOUT_MS_PROPERTY "ro.llk.timeout_ms"
+#define KHT_TIMEOUT_PROPERTY "ro.khungtask.timeout"
+#define LLK_D_TIMEOUT_MS_PROPERTY "ro.llk.D.timeout_ms"
+#define LLK_Z_TIMEOUT_MS_PROPERTY "ro.llk.Z.timeout_ms"
+#define LLK_CHECK_MS_PROPERTY "ro.llk.check_ms"
+/* LLK_CHECK_MS_DEFAULT = actual timeout_ms / LLK_CHECKS_PER_TIMEOUT_DEFAULT */
+#define LLK_CHECKS_PER_TIMEOUT_DEFAULT 5
+#define LLK_BLACKLIST_PROCESS_PROPERTY "ro.llk.blacklist.process"
+#define LLK_BLACKLIST_PROCESS_DEFAULT \
+ "0,1,2,init,[kthreadd],[khungtaskd],lmkd,lmkd.llkd,llkd,watchdogd,[watchdogd],[watchdogd/0]"
+#define LLK_BLACKLIST_PARENT_PROPERTY "ro.llk.blacklist.parent"
+#define LLK_BLACKLIST_PARENT_DEFAULT "0,2,[kthreadd]"
+#define LLK_BLACKLIST_UID_PROPERTY "ro.llk.blacklist.uid"
+#define LLK_BLACKLIST_UID_DEFAULT ""
+/* clang-format on */
+
+__END_DECLS
+
+#ifdef __cplusplus
+extern "C++" { /* In case this included wrapped with __BEGIN_DECLS */
+
+#include <chrono>
+
+__BEGIN_DECLS
+/* C++ code allowed to not specify threadname argument for this C linkage */
+bool llkInit(const char* threadname = nullptr);
+__END_DECLS
+std::chrono::milliseconds llkCheck(bool checkRunning = false);
+
+/* clang-format off */
+#define LLK_TIMEOUT_MS_DEFAULT std::chrono::duration_cast<milliseconds>(std::chrono::minutes(10))
+#define LLK_TIMEOUT_MS_MINIMUM std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::seconds(10))
+#define LLK_CHECK_MS_MINIMUM std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::seconds(1))
+/* clang-format on */
+
+} /* extern "C++" */
+#endif /* __cplusplus */
+
+#endif /* _LLKD_H_ */
diff --git a/llkd/libllkd.cpp b/llkd/libllkd.cpp
new file mode 100644
index 0000000..f357cc2
--- /dev/null
+++ b/llkd/libllkd.cpp
@@ -0,0 +1,1168 @@
+/*
+ * 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 "llkd.h"
+
+#include <ctype.h>
+#include <dirent.h> // opendir() and readdir()
+#include <errno.h>
+#include <fcntl.h>
+#include <pthread.h>
+#include <pwd.h> // getpwuid()
+#include <signal.h>
+#include <stdint.h>
+#include <sys/cdefs.h> // ___STRING, __predict_true() and _predict_false()
+#include <sys/mman.h> // mlockall()
+#include <sys/prctl.h>
+#include <sys/stat.h> // lstat()
+#include <sys/syscall.h> // __NR_getdents64
+#include <sys/sysinfo.h> // get_nprocs_conf()
+#include <sys/types.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <chrono>
+#include <ios>
+#include <sstream>
+#include <string>
+#include <unordered_map>
+#include <unordered_set>
+
+#include <android-base/file.h>
+#include <android-base/logging.h>
+#include <android-base/parseint.h>
+#include <android-base/properties.h>
+#include <android-base/strings.h>
+#include <cutils/android_get_control_file.h>
+#include <log/log_main.h>
+
+#define ARRAY_SIZE(x) (sizeof(x) / sizeof(*(x)))
+
+#define TASK_COMM_LEN 16 // internal kernel, not uapi, from .../linux/include/linux/sched.h
+
+using namespace std::chrono_literals;
+using namespace std::chrono;
+
+namespace {
+
+constexpr pid_t kernelPid = 0;
+constexpr pid_t initPid = 1;
+constexpr pid_t kthreaddPid = 2;
+
+constexpr char procdir[] = "/proc/";
+
+// Configuration
+milliseconds llkUpdate; // last check ms signature
+milliseconds llkCycle; // ms to next thread check
+bool llkEnable = LLK_ENABLE_DEFAULT; // llk daemon enabled
+bool llkRunning = false; // thread is running
+bool llkMlockall = LLK_MLOCKALL_DEFAULT; // run mlocked
+bool llkTestWithKill = LLK_KILLTEST_DEFAULT; // issue test kills
+milliseconds llkTimeoutMs = LLK_TIMEOUT_MS_DEFAULT; // default timeout
+enum { llkStateD, llkStateZ, llkNumStates }; // state indexes
+milliseconds llkStateTimeoutMs[llkNumStates]; // timeout override for each detection state
+milliseconds llkCheckMs; // checking interval to inspect any
+ // persistent live-locked states
+bool llkLowRam; // ro.config.low_ram
+bool khtEnable = LLK_ENABLE_DEFAULT; // [khungtaskd] panic
+// [khungtaskd] should have a timeout beyond the granularity of llkTimeoutMs.
+// Provides a wide angle of margin b/c khtTimeout is also its granularity.
+seconds khtTimeout = duration_cast<seconds>(llkTimeoutMs * (1 + LLK_CHECKS_PER_TIMEOUT_DEFAULT) /
+ LLK_CHECKS_PER_TIMEOUT_DEFAULT);
+
+// Blacklist variables, initialized with comma separated lists of high false
+// positive and/or dangerous references, e.g. without self restart, for pid,
+// ppid, name and uid:
+
+// list of pids, or tids or names to skip. kernel pid (0), init pid (1),
+// [kthreadd] pid (2), ourselves, "init", "[kthreadd]", "lmkd", "llkd" or
+// combinations of watchdogd in kernel and user space.
+std::unordered_set<std::string> llkBlacklistProcess;
+// list of parent pids, comm or cmdline names to skip. default:
+// kernel pid (0), [kthreadd] (2), or ourselves, enforced and implied
+std::unordered_set<std::string> llkBlacklistParent;
+// list of uids, and uid names, to skip, default nothing
+std::unordered_set<std::string> llkBlacklistUid;
+
+class dir {
+ public:
+ enum level { proc, task, numLevels };
+
+ private:
+ int fd;
+ size_t available_bytes;
+ dirent* next;
+ // each directory level picked to be just north of 4K in size
+ static constexpr size_t buffEntries = 15;
+ static dirent buff[numLevels][buffEntries];
+
+ bool fill(enum level index) {
+ if (index >= numLevels) return false;
+ if (available_bytes != 0) return true;
+ if (__predict_false(fd < 0)) return false;
+ // getdents64 has no libc wrapper
+ auto rc = TEMP_FAILURE_RETRY(syscall(__NR_getdents64, fd, buff[index], sizeof(buff[0]), 0));
+ if (rc <= 0) return false;
+ available_bytes = rc;
+ next = buff[index];
+ return true;
+ }
+
+ public:
+ dir() : fd(-1), available_bytes(0), next(nullptr) {}
+
+ explicit dir(const char* directory)
+ : fd(__predict_true(directory != nullptr)
+ ? ::open(directory, O_CLOEXEC | O_DIRECTORY | O_RDONLY)
+ : -1),
+ available_bytes(0),
+ next(nullptr) {}
+
+ explicit dir(const std::string&& directory)
+ : fd(::open(directory.c_str(), O_CLOEXEC | O_DIRECTORY | O_RDONLY)),
+ available_bytes(0),
+ next(nullptr) {}
+
+ explicit dir(const std::string& directory)
+ : fd(::open(directory.c_str(), O_CLOEXEC | O_DIRECTORY | O_RDONLY)),
+ available_bytes(0),
+ next(nullptr) {}
+
+ // Don't need any copy or move constructors.
+ explicit dir(const dir& c) = delete;
+ explicit dir(dir& c) = delete;
+ explicit dir(dir&& c) = delete;
+
+ ~dir() {
+ if (fd >= 0) {
+ ::close(fd);
+ }
+ }
+
+ operator bool() const { return fd >= 0; }
+
+ void reset(void) {
+ if (fd >= 0) {
+ ::close(fd);
+ fd = -1;
+ available_bytes = 0;
+ next = nullptr;
+ }
+ }
+
+ dir& reset(const char* directory) {
+ reset();
+ // available_bytes will _always_ be zero here as its value is
+ // intimately tied to fd < 0 or not.
+ fd = ::open(directory, O_CLOEXEC | O_DIRECTORY | O_RDONLY);
+ return *this;
+ }
+
+ void rewind(void) {
+ if (fd >= 0) {
+ ::lseek(fd, off_t(0), SEEK_SET);
+ available_bytes = 0;
+ next = nullptr;
+ }
+ }
+
+ dirent* read(enum level index = proc, dirent* def = nullptr) {
+ if (!fill(index)) return def;
+ auto ret = next;
+ available_bytes -= next->d_reclen;
+ next = reinterpret_cast<dirent*>(reinterpret_cast<char*>(next) + next->d_reclen);
+ return ret;
+ }
+} llkTopDirectory;
+
+dirent dir::buff[dir::numLevels][dir::buffEntries];
+
+// helper functions
+
+bool llkIsMissingExeLink(pid_t tid) {
+ char c;
+ // CAP_SYS_PTRACE is required to prevent ret == -1, but ENOENT is signal
+ auto ret = ::readlink((procdir + std::to_string(tid) + "/exe").c_str(), &c, sizeof(c));
+ return (ret == -1) && (errno == ENOENT);
+}
+
+// Common routine where caller accepts empty content as error/passthrough.
+// Reduces the churn of reporting read errors in the callers.
+std::string ReadFile(std::string&& path) {
+ std::string content;
+ if (!android::base::ReadFileToString(path, &content)) {
+ PLOG(DEBUG) << "Read " << path << " failed";
+ content = "";
+ }
+ return content;
+}
+
+std::string llkProcGetName(pid_t tid, const char* node = "/cmdline") {
+ std::string content = ReadFile(procdir + std::to_string(tid) + node);
+ static constexpr char needles[] = " \t\r\n"; // including trailing nul
+ auto pos = content.find_first_of(needles, 0, sizeof(needles));
+ if (pos != std::string::npos) {
+ content.erase(pos);
+ }
+ return content;
+}
+
+uid_t llkProcGetUid(pid_t tid) {
+ // Get the process' uid. The following read from /status is admittedly
+ // racy, prone to corruption due to shape-changes. The consequences are
+ // not catastrophic as we sample a few times before taking action.
+ //
+ // If /loginuid worked on reliably, or on Android (all tasks report -1)...
+ // Android lmkd causes /cgroup to contain memory:/<dom>/uid_<uid>/pid_<pid>
+ // which is tighter, but also not reliable.
+ std::string content = ReadFile(procdir + std::to_string(tid) + "/status");
+ static constexpr char Uid[] = "\nUid:";
+ auto pos = content.find(Uid);
+ if (pos == std::string::npos) {
+ return -1;
+ }
+ pos += ::strlen(Uid);
+ while ((pos < content.size()) && ::isblank(content[pos])) {
+ ++pos;
+ }
+ content.erase(0, pos);
+ for (pos = 0; (pos < content.size()) && ::isdigit(content[pos]); ++pos) {
+ ;
+ }
+ // Content of form 'Uid: 0 0 0 0', newline is error
+ if ((pos >= content.size()) || !::isblank(content[pos])) {
+ return -1;
+ }
+ content.erase(pos);
+ uid_t ret;
+ if (!android::base::ParseInt(content, &ret, uid_t(0))) {
+ return -1;
+ }
+ return ret;
+}
+
+struct proc {
+ pid_t tid; // monitored thread id (in Z or D state).
+ nanoseconds schedUpdate; // /proc/<tid>/sched "se.avg.lastUpdateTime",
+ uint64_t nrSwitches; // /proc/<tid>/sched "nr_switches" for
+ // refined ABA problem detection, determine
+ // forward scheduling progress.
+ milliseconds update; // llkUpdate millisecond signature of last.
+ milliseconds count; // duration in state.
+ pid_t pid; // /proc/<pid> before iterating through
+ // /proc/<pid>/task/<tid> for threads.
+ pid_t ppid; // /proc/<tid>/stat field 4 parent pid.
+ uid_t uid; // /proc/<tid>/status Uid: field.
+ unsigned time; // sum of /proc/<tid>/stat field 14 utime &
+ // 15 stime for coarse ABA problem detection.
+ std::string cmdline; // cached /cmdline content
+ char state; // /proc/<tid>/stat field 3: Z or D
+ // (others we do not monitor: S, R, T or ?)
+ char comm[TASK_COMM_LEN + 3]; // space for adding '[' and ']'
+ bool exeMissingValid; // exeMissing has been cached
+ bool cmdlineValid; // cmdline has been cached
+ bool updated; // cleared before monitoring pass.
+ bool killed; // sent a kill to this thread, next panic...
+
+ void setComm(const char* _comm) { strncpy(comm + 1, _comm, sizeof(comm) - 2); }
+
+ proc(pid_t tid, pid_t pid, pid_t ppid, const char* _comm, int time, char state)
+ : tid(tid),
+ schedUpdate(0),
+ nrSwitches(0),
+ update(llkUpdate),
+ count(0),
+ pid(pid),
+ ppid(ppid),
+ uid(-1),
+ time(time),
+ state(state),
+ exeMissingValid(false),
+ cmdlineValid(false),
+ updated(true),
+ killed(!llkTestWithKill) {
+ memset(comm, '\0', sizeof(comm));
+ setComm(_comm);
+ }
+
+ const char* getComm(void) {
+ if (comm[1] == '\0') { // comm Valid?
+ strncpy(comm + 1, llkProcGetName(tid, "/comm").c_str(), sizeof(comm) - 2);
+ }
+ if (!exeMissingValid) {
+ if (llkIsMissingExeLink(tid)) {
+ comm[0] = '[';
+ }
+ exeMissingValid = true;
+ }
+ size_t len = strlen(comm + 1);
+ if (__predict_true(len < (sizeof(comm) - 1))) {
+ if (comm[0] == '[') {
+ if ((comm[len] != ']') && __predict_true(len < (sizeof(comm) - 2))) {
+ comm[++len] = ']';
+ comm[++len] = '\0';
+ }
+ } else {
+ if (comm[len] == ']') {
+ comm[len] = '\0';
+ }
+ }
+ }
+ return &comm[comm[0] != '['];
+ }
+
+ const char* getCmdline(void) {
+ if (!cmdlineValid) {
+ cmdline = llkProcGetName(tid);
+ cmdlineValid = true;
+ }
+ return cmdline.c_str();
+ }
+
+ uid_t getUid(void) {
+ if (uid <= 0) { // Churn on root user, because most likely to setuid()
+ uid = llkProcGetUid(tid);
+ }
+ return uid;
+ }
+
+ void reset(void) { // reset cache, if we detected pid rollover
+ uid = -1;
+ state = '?';
+ cmdline = "";
+ comm[0] = '\0';
+ exeMissingValid = false;
+ cmdlineValid = false;
+ }
+};
+
+std::unordered_map<pid_t, proc> tids;
+
+// Check range and setup defaults, in order of propagation:
+// llkTimeoutMs
+// llkCheckMs
+// ...
+// KISS to keep it all self-contained, and called multiple times as parameters
+// are interpreted so that defaults, llkCheckMs and llkCycle make sense.
+void llkValidate() {
+ if (llkTimeoutMs == 0ms) {
+ llkTimeoutMs = LLK_TIMEOUT_MS_DEFAULT;
+ }
+ llkTimeoutMs = std::max(llkTimeoutMs, LLK_TIMEOUT_MS_MINIMUM);
+ if (llkCheckMs == 0ms) {
+ llkCheckMs = llkTimeoutMs / LLK_CHECKS_PER_TIMEOUT_DEFAULT;
+ }
+ llkCheckMs = std::min(llkCheckMs, llkTimeoutMs);
+
+ for (size_t state = 0; state < ARRAY_SIZE(llkStateTimeoutMs); ++state) {
+ if (llkStateTimeoutMs[state] == 0ms) {
+ llkStateTimeoutMs[state] = llkTimeoutMs;
+ }
+ llkStateTimeoutMs[state] =
+ std::min(std::max(llkStateTimeoutMs[state], LLK_TIMEOUT_MS_MINIMUM), llkTimeoutMs);
+ llkCheckMs = std::min(llkCheckMs, llkStateTimeoutMs[state]);
+ }
+
+ llkCheckMs = std::max(llkCheckMs, LLK_CHECK_MS_MINIMUM);
+ if (llkCycle == 0ms) {
+ llkCycle = llkCheckMs;
+ }
+ llkCycle = std::min(llkCycle, llkCheckMs);
+}
+
+milliseconds llkGetTimespecDiffMs(timespec* from, timespec* to) {
+ return duration_cast<milliseconds>(seconds(to->tv_sec - from->tv_sec)) +
+ duration_cast<milliseconds>(nanoseconds(to->tv_nsec - from->tv_nsec));
+}
+
+std::string llkProcGetName(pid_t tid, const char* comm, const char* cmdline) {
+ if ((cmdline != nullptr) && (*cmdline != '\0')) {
+ return cmdline;
+ }
+ if ((comm != nullptr) && (*comm != '\0')) {
+ return comm;
+ }
+
+ // UNLIKELY! Here because killed before we kill it?
+ // Assume change is afoot, do not call llkTidAlloc
+
+ // cmdline ?
+ std::string content = llkProcGetName(tid);
+ if (content.size() != 0) {
+ return content;
+ }
+ // Comm instead?
+ content = llkProcGetName(tid, "/comm");
+ if (llkIsMissingExeLink(tid) && (content.size() != 0)) {
+ return '[' + content + ']';
+ }
+ return content;
+}
+
+int llkKillOneProcess(pid_t pid, char state, pid_t tid, const char* tcomm = nullptr,
+ const char* tcmdline = nullptr, const char* pcomm = nullptr,
+ const char* pcmdline = nullptr) {
+ std::string forTid;
+ if (tid != pid) {
+ forTid = " for '" + llkProcGetName(tid, tcomm, tcmdline) + "' (" + std::to_string(tid) + ")";
+ }
+ LOG(INFO) << "Killing '" << llkProcGetName(pid, pcomm, pcmdline) << "' (" << pid
+ << ") to check forward scheduling progress in " << state << " state" << forTid;
+ // CAP_KILL required
+ errno = 0;
+ auto r = ::kill(pid, SIGKILL);
+ if (r) {
+ PLOG(ERROR) << "kill(" << pid << ")=" << r << ' ';
+ }
+
+ return r;
+}
+
+// Kill one process
+int llkKillOneProcess(pid_t pid, proc* tprocp) {
+ return llkKillOneProcess(pid, tprocp->state, tprocp->tid, tprocp->getComm(),
+ tprocp->getCmdline());
+}
+
+// Kill one process specified by kprocp
+int llkKillOneProcess(proc* kprocp, proc* tprocp) {
+ if (kprocp == nullptr) {
+ return -2;
+ }
+
+ return llkKillOneProcess(kprocp->tid, tprocp->state, tprocp->tid, tprocp->getComm(),
+ tprocp->getCmdline(), kprocp->getComm(), kprocp->getCmdline());
+}
+
+// Acquire file descriptor from environment, or open and cache it.
+// NB: cache is unnecessary in our current context, pedantically
+// required to prevent leakage of file descriptors in the future.
+int llkFileToWriteFd(const std::string& file) {
+ static std::unordered_map<std::string, int> cache;
+ auto search = cache.find(file);
+ if (search != cache.end()) return search->second;
+ auto fd = android_get_control_file(file.c_str());
+ if (fd >= 0) return fd;
+ fd = TEMP_FAILURE_RETRY(::open(file.c_str(), O_WRONLY | O_CLOEXEC));
+ if (fd >= 0) cache.emplace(std::make_pair(file, fd));
+ return fd;
+}
+
+// Wrap android::base::WriteStringToFile to use android_get_control_file.
+bool llkWriteStringToFile(const std::string& string, const std::string& file) {
+ auto fd = llkFileToWriteFd(file);
+ if (fd < 0) return false;
+ return android::base::WriteStringToFd(string, fd);
+}
+
+bool llkWriteStringToFileConfirm(const std::string& string, const std::string& file) {
+ auto fd = llkFileToWriteFd(file);
+ auto ret = (fd < 0) ? false : android::base::WriteStringToFd(string, fd);
+ std::string content;
+ if (!android::base::ReadFileToString(file, &content)) return ret;
+ return android::base::Trim(content) == string;
+}
+
+void llkPanicKernel(bool dump, pid_t tid, const char* state) __noreturn;
+void llkPanicKernel(bool dump, pid_t tid, const char* state) {
+ auto sysrqTriggerFd = llkFileToWriteFd("/proc/sysrq-trigger");
+ if (sysrqTriggerFd < 0) {
+ // DYB
+ llkKillOneProcess(initPid, 'R', tid);
+ // The answer to life, the universe and everything
+ ::exit(42);
+ // NOTREACHED
+ }
+ ::sync();
+ if (dump) {
+ // Show all locks that are held
+ android::base::WriteStringToFd("d", sysrqTriggerFd);
+ // This can trigger hardware watchdog, that is somewhat _ok_.
+ // But useless if pstore configured for <256KB, low ram devices ...
+ if (!llkLowRam) {
+ android::base::WriteStringToFd("t", sysrqTriggerFd);
+ }
+ ::usleep(200000); // let everything settle
+ }
+ llkWriteStringToFile(std::string("SysRq : Trigger a crash : 'livelock,") + state + "'\n",
+ "/dev/kmsg");
+ android::base::WriteStringToFd("c", sysrqTriggerFd);
+ // NOTREACHED
+ // DYB
+ llkKillOneProcess(initPid, 'R', tid);
+ // I sat at my desk, stared into the garden and thought '42 will do'.
+ // I typed it out. End of story
+ ::exit(42);
+ // NOTREACHED
+}
+
+void llkAlarmHandler(int) {
+ llkPanicKernel(false, ::getpid(), "alarm");
+}
+
+milliseconds GetUintProperty(const std::string& key, milliseconds def) {
+ return milliseconds(android::base::GetUintProperty(key, static_cast<uint64_t>(def.count()),
+ static_cast<uint64_t>(def.max().count())));
+}
+
+seconds GetUintProperty(const std::string& key, seconds def) {
+ return seconds(android::base::GetUintProperty(key, static_cast<uint64_t>(def.count()),
+ static_cast<uint64_t>(def.max().count())));
+}
+
+proc* llkTidLookup(pid_t tid) {
+ auto search = tids.find(tid);
+ if (search == tids.end()) {
+ return nullptr;
+ }
+ return &search->second;
+}
+
+void llkTidRemove(pid_t tid) {
+ tids.erase(tid);
+}
+
+proc* llkTidAlloc(pid_t tid, pid_t pid, pid_t ppid, const char* comm, int time, char state) {
+ auto it = tids.emplace(std::make_pair(tid, proc(tid, pid, ppid, comm, time, state)));
+ return &it.first->second;
+}
+
+std::string llkFormat(milliseconds ms) {
+ auto sec = duration_cast<seconds>(ms);
+ std::ostringstream s;
+ s << sec.count() << '.';
+ auto f = s.fill('0');
+ auto w = s.width(3);
+ s << std::right << (ms - sec).count();
+ s.width(w);
+ s.fill(f);
+ s << 's';
+ return s.str();
+}
+
+std::string llkFormat(seconds s) {
+ return std::to_string(s.count()) + 's';
+}
+
+std::string llkFormat(bool flag) {
+ return flag ? "true" : "false";
+}
+
+std::string llkFormat(const std::unordered_set<std::string>& blacklist) {
+ std::string ret;
+ for (auto entry : blacklist) {
+ if (ret.size()) {
+ ret += ",";
+ }
+ ret += entry;
+ }
+ return ret;
+}
+
+// We only officially support comma separators, but wetware being what they
+// are will take some liberty and I do not believe they should be punished.
+std::unordered_set<std::string> llkSplit(const std::string& s,
+ const std::string& delimiters = ", \t:") {
+ std::unordered_set<std::string> result;
+
+ size_t base = 0;
+ size_t found;
+ while (true) {
+ found = s.find_first_of(delimiters, base);
+ result.emplace(s.substr(base, found - base));
+ if (found == s.npos) break;
+ base = found + 1;
+ }
+ return result;
+}
+
+bool llkSkipName(const std::string& name,
+ const std::unordered_set<std::string>& blacklist = llkBlacklistProcess) {
+ if ((name.size() == 0) || (blacklist.size() == 0)) {
+ return false;
+ }
+
+ return blacklist.find(name) != blacklist.end();
+}
+
+bool llkSkipPid(pid_t pid) {
+ return llkSkipName(std::to_string(pid), llkBlacklistProcess);
+}
+
+bool llkSkipPpid(pid_t ppid) {
+ return llkSkipName(std::to_string(ppid), llkBlacklistParent);
+}
+
+bool llkSkipUid(uid_t uid) {
+ // Match by number?
+ if (llkSkipName(std::to_string(uid), llkBlacklistUid)) {
+ return true;
+ }
+
+ // Match by name?
+ auto pwd = ::getpwuid(uid);
+ return (pwd != nullptr) && __predict_true(pwd->pw_name != nullptr) &&
+ __predict_true(pwd->pw_name[0] != '\0') && llkSkipName(pwd->pw_name, llkBlacklistUid);
+}
+
+bool getValidTidDir(dirent* dp, std::string* piddir) {
+ if (!::isdigit(dp->d_name[0])) {
+ return false;
+ }
+
+ // Corner case can not happen in reality b/c of above ::isdigit check
+ if (__predict_false(dp->d_type != DT_DIR)) {
+ if (__predict_false(dp->d_type == DT_UNKNOWN)) { // can't b/c procfs
+ struct stat st;
+ *piddir = procdir;
+ *piddir += dp->d_name;
+ return (lstat(piddir->c_str(), &st) == 0) && (st.st_mode & S_IFDIR);
+ }
+ return false;
+ }
+
+ *piddir = procdir;
+ *piddir += dp->d_name;
+ return true;
+}
+
+bool llkIsMonitorState(char state) {
+ return (state == 'Z') || (state == 'D');
+}
+
+// returns -1 if not found
+long long getSchedValue(const std::string& schedString, const char* key) {
+ auto pos = schedString.find(key);
+ if (pos == std::string::npos) {
+ return -1;
+ }
+ pos = schedString.find(':', pos);
+ if (__predict_false(pos == std::string::npos)) {
+ return -1;
+ }
+ while ((++pos < schedString.size()) && ::isblank(schedString[pos])) {
+ ;
+ }
+ long long ret;
+ if (!android::base::ParseInt(schedString.substr(pos), &ret, static_cast<long long>(0))) {
+ return -1;
+ }
+ return ret;
+}
+
+// Primary ABA mitigation watching last time schedule activity happened
+void llkCheckSchedUpdate(proc* procp, const std::string& piddir) {
+ // Audit finds /proc/<tid>/sched is just over 1K, and
+ // is rarely larger than 2K, even less on Android.
+ // For example, the "se.avg.lastUpdateTime" field we are
+ // interested in typically within the primary set in
+ // the first 1K.
+ //
+ // Proc entries can not be read >1K atomically via libbase,
+ // but if there are problems we assume at least a few
+ // samples of reads occur before we take any real action.
+ std::string schedString = ReadFile(piddir + "/sched");
+ if (schedString.size() == 0) {
+ // /schedstat is not as standardized, but in 3.1+
+ // Android devices, the third field is nr_switches
+ // from /sched:
+ schedString = ReadFile(piddir + "/schedstat");
+ if (schedString.size() == 0) {
+ return;
+ }
+ auto val = static_cast<unsigned long long>(-1);
+ if (((::sscanf(schedString.c_str(), "%*d %*d %llu", &val)) == 1) &&
+ (val != static_cast<unsigned long long>(-1)) && (val != 0) &&
+ (val != procp->nrSwitches)) {
+ procp->nrSwitches = val;
+ procp->count = 0ms;
+ procp->killed = !llkTestWithKill;
+ }
+ return;
+ }
+
+ auto val = getSchedValue(schedString, "\nse.avg.lastUpdateTime");
+ if (val == -1) {
+ val = getSchedValue(schedString, "\nse.svg.last_update_time");
+ }
+ if (val != -1) {
+ auto schedUpdate = nanoseconds(val);
+ if (schedUpdate != procp->schedUpdate) {
+ procp->schedUpdate = schedUpdate;
+ procp->count = 0ms;
+ procp->killed = !llkTestWithKill;
+ }
+ }
+
+ val = getSchedValue(schedString, "\nnr_switches");
+ if (val != -1) {
+ if (static_cast<uint64_t>(val) != procp->nrSwitches) {
+ procp->nrSwitches = val;
+ procp->count = 0ms;
+ procp->killed = !llkTestWithKill;
+ }
+ }
+}
+
+void llkLogConfig(void) {
+ LOG(INFO) << "ro.config.low_ram=" << llkFormat(llkLowRam) << "\n"
+ << LLK_ENABLE_PROPERTY "=" << llkFormat(llkEnable) << "\n"
+ << KHT_ENABLE_PROPERTY "=" << llkFormat(khtEnable) << "\n"
+ << LLK_MLOCKALL_PROPERTY "=" << llkFormat(llkMlockall) << "\n"
+ << LLK_KILLTEST_PROPERTY "=" << llkFormat(llkTestWithKill) << "\n"
+ << KHT_TIMEOUT_PROPERTY "=" << llkFormat(khtTimeout) << "\n"
+ << LLK_TIMEOUT_MS_PROPERTY "=" << llkFormat(llkTimeoutMs) << "\n"
+ << LLK_D_TIMEOUT_MS_PROPERTY "=" << llkFormat(llkStateTimeoutMs[llkStateD]) << "\n"
+ << LLK_Z_TIMEOUT_MS_PROPERTY "=" << llkFormat(llkStateTimeoutMs[llkStateZ]) << "\n"
+ << LLK_CHECK_MS_PROPERTY "=" << llkFormat(llkCheckMs) << "\n"
+ << LLK_BLACKLIST_PROCESS_PROPERTY "=" << llkFormat(llkBlacklistProcess) << "\n"
+ << LLK_BLACKLIST_PARENT_PROPERTY "=" << llkFormat(llkBlacklistParent) << "\n"
+ << LLK_BLACKLIST_UID_PROPERTY "=" << llkFormat(llkBlacklistUid);
+}
+
+void* llkThread(void* obj) {
+ LOG(INFO) << "started";
+
+ std::string name = std::to_string(::gettid());
+ if (!llkSkipName(name)) {
+ llkBlacklistProcess.emplace(name);
+ }
+ name = static_cast<const char*>(obj);
+ prctl(PR_SET_NAME, name.c_str());
+ if (__predict_false(!llkSkipName(name))) {
+ llkBlacklistProcess.insert(name);
+ }
+ // No longer modifying llkBlacklistProcess.
+ llkRunning = true;
+ llkLogConfig();
+ while (llkRunning) {
+ ::usleep(duration_cast<microseconds>(llkCheck(true)).count());
+ }
+ // NOTREACHED
+ LOG(INFO) << "exiting";
+ return nullptr;
+}
+
+} // namespace
+
+milliseconds llkCheck(bool checkRunning) {
+ if (!llkEnable || (checkRunning != llkRunning)) {
+ return milliseconds::max();
+ }
+
+ // Reset internal watchdog, which is a healthy engineering margin of
+ // double the maximum wait or cycle time for the mainloop that calls us.
+ //
+ // This alarm is effectively the live lock detection of llkd, as
+ // we understandably can not monitor ourselves otherwise.
+ ::alarm(duration_cast<seconds>(llkTimeoutMs * 2).count());
+
+ // kernel jiffy precision fastest acquisition
+ static timespec last;
+ timespec now;
+ ::clock_gettime(CLOCK_MONOTONIC_COARSE, &now);
+ auto ms = llkGetTimespecDiffMs(&last, &now);
+ if (ms < llkCycle) {
+ return llkCycle - ms;
+ }
+ last = now;
+
+ LOG(VERBOSE) << "opendir(\"" << procdir << "\")";
+ if (__predict_false(!llkTopDirectory)) {
+ // gid containing AID_READPROC required
+ llkTopDirectory.reset(procdir);
+ if (__predict_false(!llkTopDirectory)) {
+ // Most likely reason we could be here is a resource limit.
+ // Keep our processing down to a minimum, but not so low that
+ // we do not recover in a timely manner should the issue be
+ // transitory.
+ LOG(DEBUG) << "opendir(\"" << procdir << "\") failed";
+ return llkTimeoutMs;
+ }
+ }
+
+ for (auto& it : tids) {
+ it.second.updated = false;
+ }
+
+ auto prevUpdate = llkUpdate;
+ llkUpdate += ms;
+ ms -= llkCycle;
+ auto myPid = ::getpid();
+ auto myTid = ::gettid();
+ for (auto dp = llkTopDirectory.read(); dp != nullptr; dp = llkTopDirectory.read()) {
+ std::string piddir;
+
+ if (!getValidTidDir(dp, &piddir)) {
+ continue;
+ }
+
+ // Get the process tasks
+ std::string taskdir = piddir + "/task/";
+ int pid = -1;
+ LOG(VERBOSE) << "+opendir(\"" << taskdir << "\")";
+ dir taskDirectory(taskdir);
+ if (__predict_false(!taskDirectory)) {
+ LOG(DEBUG) << "+opendir(\"" << taskdir << "\") failed";
+ }
+ for (auto tp = taskDirectory.read(dir::task, dp); tp != nullptr;
+ tp = taskDirectory.read(dir::task)) {
+ if (!getValidTidDir(tp, &piddir)) {
+ continue;
+ }
+
+ // Get the process stat
+ std::string stat = ReadFile(piddir + "/stat");
+ if (stat.size() == 0) {
+ continue;
+ }
+ unsigned tid = -1;
+ char pdir[TASK_COMM_LEN + 1];
+ char state = '?';
+ unsigned ppid = -1;
+ unsigned utime = -1;
+ unsigned stime = -1;
+ int dummy;
+ pdir[0] = '\0';
+ // tid should not change value
+ auto match = ::sscanf(
+ stat.c_str(),
+ "%u (%" ___STRING(
+ TASK_COMM_LEN) "[^)]) %c %u %*d %*d %*d %*d %*d %*d %*d %*d %*d %u %u %d",
+ &tid, pdir, &state, &ppid, &utime, &stime, &dummy);
+ if (pid == -1) {
+ pid = tid;
+ }
+ LOG(VERBOSE) << "match " << match << ' ' << tid << " (" << pdir << ") " << state << ' '
+ << ppid << " ... " << utime << ' ' << stime << ' ' << dummy;
+ if (match != 7) {
+ continue;
+ }
+
+ auto procp = llkTidLookup(tid);
+ if (procp == nullptr) {
+ procp = llkTidAlloc(tid, pid, ppid, pdir, utime + stime, state);
+ } else {
+ // comm can change ...
+ procp->setComm(pdir);
+ procp->updated = true;
+ // pid/ppid/tid wrap?
+ if (((procp->update != prevUpdate) && (procp->update != llkUpdate)) ||
+ (procp->ppid != ppid) || (procp->pid != pid)) {
+ procp->reset();
+ } else if (procp->time != (utime + stime)) { // secondary ABA.
+ // watching utime+stime granularity jiffy
+ procp->state = '?';
+ }
+ procp->update = llkUpdate;
+ procp->pid = pid;
+ procp->ppid = ppid;
+ procp->time = utime + stime;
+ if (procp->state != state) {
+ procp->count = 0ms;
+ procp->killed = !llkTestWithKill;
+ procp->state = state;
+ } else {
+ procp->count += llkCycle;
+ }
+ }
+
+ // Filter checks in intuitive order of CPU cost to evaluate
+ // If tid unique continue, if ppid or pid unique break
+
+ if (pid == myPid) {
+ break;
+ }
+ if (!llkIsMonitorState(state)) {
+ continue;
+ }
+ if ((tid == myTid) || llkSkipPid(tid)) {
+ continue;
+ }
+ if (llkSkipPpid(ppid)) {
+ break;
+ }
+
+ if (llkSkipName(procp->getComm())) {
+ continue;
+ }
+ if (llkSkipName(procp->getCmdline())) {
+ break;
+ }
+
+ auto pprocp = llkTidLookup(ppid);
+ if (pprocp == nullptr) {
+ pprocp = llkTidAlloc(ppid, ppid, 0, "", 0, '?');
+ }
+ if ((pprocp != nullptr) && (llkSkipName(pprocp->getComm(), llkBlacklistParent) ||
+ llkSkipName(pprocp->getCmdline(), llkBlacklistParent))) {
+ break;
+ }
+
+ if ((llkBlacklistUid.size() != 0) && llkSkipUid(procp->getUid())) {
+ continue;
+ }
+
+ // ABA mitigation watching last time schedule activity happened
+ llkCheckSchedUpdate(procp, piddir);
+
+ // Can only fall through to here if registered D or Z state !!!
+ if (procp->count < llkStateTimeoutMs[(state == 'Z') ? llkStateZ : llkStateD]) {
+ LOG(VERBOSE) << state << ' ' << llkFormat(procp->count) << ' ' << ppid << "->"
+ << pid << "->" << tid << ' ' << procp->getComm();
+ continue;
+ }
+
+ // We have to kill it to determine difference between live lock
+ // and persistent state blocked on a resource. Is there something
+ // wrong with a process that has no forward scheduling progress in
+ // Z or D? Yes, generally means improper accounting in the
+ // process, but not always ...
+ //
+ // Whomever we hit with a test kill must accept the Android
+ // Aphorism that everything can be burned to the ground and
+ // must survive.
+ if (procp->killed == false) {
+ procp->killed = true;
+ // confirm: re-read uid before committing to a panic.
+ procp->uid = -1;
+ switch (state) {
+ case 'Z': // kill ppid to free up a Zombie
+ // Killing init will kernel panic without diagnostics
+ // so skip right to controlled kernel panic with
+ // diagnostics.
+ if (ppid == initPid) {
+ break;
+ }
+ LOG(WARNING) << "Z " << llkFormat(procp->count) << ' ' << ppid << "->"
+ << pid << "->" << tid << ' ' << procp->getComm() << " [kill]";
+ if ((llkKillOneProcess(pprocp, procp) >= 0) ||
+ (llkKillOneProcess(ppid, procp) >= 0)) {
+ continue;
+ }
+ break;
+
+ case 'D': // kill tid to free up an uninterruptible D
+ // If ABA is doing its job, we would not need or
+ // want the following. Test kill is a Hail Mary
+ // to make absolutely sure there is no forward
+ // scheduling progress. The cost when ABA is
+ // not working is we kill a process that likes to
+ // stay in 'D' state, instead of panicing the
+ // kernel (worse).
+ LOG(WARNING) << "D " << llkFormat(procp->count) << ' ' << pid << "->" << tid
+ << ' ' << procp->getComm() << " [kill]";
+ if ((llkKillOneProcess(llkTidLookup(pid), procp) >= 0) ||
+ (llkKillOneProcess(pid, 'D', tid) >= 0) ||
+ (llkKillOneProcess(procp, procp) >= 0) ||
+ (llkKillOneProcess(tid, 'D', tid) >= 0)) {
+ continue;
+ }
+ break;
+ }
+ }
+ // We are here because we have confirmed kernel live-lock
+ LOG(ERROR) << state << ' ' << llkFormat(procp->count) << ' ' << ppid << "->" << pid
+ << "->" << tid << ' ' << procp->getComm() << " [panic]";
+ llkPanicKernel(true, tid, (state == 'Z') ? "zombie" : "driver");
+ }
+ LOG(VERBOSE) << "+closedir()";
+ }
+ llkTopDirectory.rewind();
+ LOG(VERBOSE) << "closedir()";
+
+ // garbage collection of old process references
+ for (auto p = tids.begin(); p != tids.end();) {
+ if (!p->second.updated) {
+ IF_ALOG(LOG_VERBOSE, LOG_TAG) {
+ std::string ppidCmdline = llkProcGetName(p->second.ppid, nullptr, nullptr);
+ if (ppidCmdline.size()) {
+ ppidCmdline = "(" + ppidCmdline + ")";
+ }
+ std::string pidCmdline;
+ if (p->second.pid != p->second.tid) {
+ pidCmdline = llkProcGetName(p->second.pid, nullptr, p->second.getCmdline());
+ if (pidCmdline.size()) {
+ pidCmdline = "(" + pidCmdline + ")";
+ }
+ }
+ std::string tidCmdline =
+ llkProcGetName(p->second.tid, p->second.getComm(), p->second.getCmdline());
+ if (tidCmdline.size()) {
+ tidCmdline = "(" + tidCmdline + ")";
+ }
+ LOG(VERBOSE) << "thread " << p->second.ppid << ppidCmdline << "->" << p->second.pid
+ << pidCmdline << "->" << p->second.tid << tidCmdline << " removed";
+ }
+ p = tids.erase(p);
+ } else {
+ ++p;
+ }
+ }
+ if (__predict_false(tids.empty())) {
+ llkTopDirectory.reset();
+ }
+
+ llkCycle = llkCheckMs;
+
+ timespec end;
+ ::clock_gettime(CLOCK_MONOTONIC_COARSE, &end);
+ auto milli = llkGetTimespecDiffMs(&now, &end);
+ LOG((milli > 10s) ? ERROR : (milli > 1s) ? WARNING : VERBOSE) << "sample " << llkFormat(milli);
+
+ // cap to minimum sleep for 1 second since last cycle
+ if (llkCycle < (ms + 1s)) {
+ return 1s;
+ }
+ return llkCycle - ms;
+}
+
+unsigned llkCheckMilliseconds() {
+ return duration_cast<milliseconds>(llkCheck()).count();
+}
+
+bool llkInit(const char* threadname) {
+ llkLowRam = android::base::GetBoolProperty("ro.config.low_ram", false);
+ if (!LLK_ENABLE_DEFAULT && android::base::GetBoolProperty("ro.debuggable", false)) {
+ llkEnable = android::base::GetProperty(LLK_ENABLE_PROPERTY, "eng") == "eng";
+ khtEnable = android::base::GetProperty(KHT_ENABLE_PROPERTY, "eng") == "eng";
+ }
+ llkEnable = android::base::GetBoolProperty(LLK_ENABLE_PROPERTY, llkEnable);
+ if (llkEnable && !llkTopDirectory.reset(procdir)) {
+ // Most likely reason we could be here is llkd was started
+ // incorrectly without the readproc permissions. Keep our
+ // processing down to a minimum.
+ llkEnable = false;
+ }
+ khtEnable = android::base::GetBoolProperty(KHT_ENABLE_PROPERTY, khtEnable);
+ llkMlockall = android::base::GetBoolProperty(LLK_MLOCKALL_PROPERTY, llkMlockall);
+ llkTestWithKill = android::base::GetBoolProperty(LLK_KILLTEST_PROPERTY, llkTestWithKill);
+ // if LLK_TIMOUT_MS_PROPERTY was not set, we will use a set
+ // KHT_TIMEOUT_PROPERTY as co-operative guidance for the default value.
+ khtTimeout = GetUintProperty(KHT_TIMEOUT_PROPERTY, khtTimeout);
+ if (khtTimeout == 0s) {
+ khtTimeout = duration_cast<seconds>(llkTimeoutMs * (1 + LLK_CHECKS_PER_TIMEOUT_DEFAULT) /
+ LLK_CHECKS_PER_TIMEOUT_DEFAULT);
+ }
+ llkTimeoutMs =
+ khtTimeout * LLK_CHECKS_PER_TIMEOUT_DEFAULT / (1 + LLK_CHECKS_PER_TIMEOUT_DEFAULT);
+ llkTimeoutMs = GetUintProperty(LLK_TIMEOUT_MS_PROPERTY, llkTimeoutMs);
+ llkValidate(); // validate llkTimeoutMs, llkCheckMs and llkCycle
+ llkStateTimeoutMs[llkStateD] = GetUintProperty(LLK_D_TIMEOUT_MS_PROPERTY, llkTimeoutMs);
+ llkStateTimeoutMs[llkStateZ] = GetUintProperty(LLK_Z_TIMEOUT_MS_PROPERTY, llkTimeoutMs);
+ llkCheckMs = GetUintProperty(LLK_CHECK_MS_PROPERTY, llkCheckMs);
+ llkValidate(); // validate all (effectively minus llkTimeoutMs)
+ std::string defaultBlacklistProcess(
+ std::to_string(kernelPid) + "," + std::to_string(initPid) + "," +
+ std::to_string(kthreaddPid) + "," + std::to_string(::getpid()) + "," +
+ std::to_string(::gettid()) + "," LLK_BLACKLIST_PROCESS_DEFAULT);
+ if (threadname) {
+ defaultBlacklistProcess += std::string(",") + threadname;
+ }
+ for (int cpu = 1; cpu < get_nprocs_conf(); ++cpu) {
+ defaultBlacklistProcess += ",[watchdog/" + std::to_string(cpu) + "]";
+ }
+ defaultBlacklistProcess =
+ android::base::GetProperty(LLK_BLACKLIST_PROCESS_PROPERTY, defaultBlacklistProcess);
+ llkBlacklistProcess = llkSplit(defaultBlacklistProcess);
+ if (!llkSkipName("[khungtaskd]")) { // ALWAYS ignore as special
+ llkBlacklistProcess.emplace("[khungtaskd]");
+ }
+ llkBlacklistParent = llkSplit(android::base::GetProperty(
+ LLK_BLACKLIST_PARENT_PROPERTY, std::to_string(kernelPid) + "," + std::to_string(kthreaddPid) +
+ "," LLK_BLACKLIST_PARENT_DEFAULT));
+ llkBlacklistUid =
+ llkSplit(android::base::GetProperty(LLK_BLACKLIST_UID_PROPERTY, LLK_BLACKLIST_UID_DEFAULT));
+
+ // internal watchdog
+ ::signal(SIGALRM, llkAlarmHandler);
+
+ // kernel hung task configuration? Otherwise leave it as-is
+ if (khtEnable) {
+ // EUID must be AID_ROOT to write to /proc/sys/kernel/ nodes, there
+ // are no capability overrides. For security reasons we do not want
+ // to run as AID_ROOT. We may not be able to write them successfully,
+ // we will try, but the least we can do is read the values back to
+ // confirm expectations and report whether configured or not.
+ auto configured = llkWriteStringToFileConfirm(std::to_string(khtTimeout.count()),
+ "/proc/sys/kernel/hung_task_timeout_secs");
+ if (configured) {
+ llkWriteStringToFile("65535", "/proc/sys/kernel/hung_task_warnings");
+ llkWriteStringToFile("65535", "/proc/sys/kernel/hung_task_check_count");
+ configured = llkWriteStringToFileConfirm("1", "/proc/sys/kernel/hung_task_panic");
+ }
+ if (configured) {
+ LOG(INFO) << "[khungtaskd] configured";
+ } else {
+ LOG(WARNING) << "[khungtaskd] not configurable";
+ }
+ }
+
+ bool logConfig = true;
+ if (llkEnable) {
+ if (llkMlockall &&
+ // MCL_ONFAULT pins pages as they fault instead of loading
+ // everything immediately all at once. (Which would be bad,
+ // because as of this writing, we have a lot of mapped pages we
+ // never use.) Old kernels will see MCL_ONFAULT and fail with
+ // EINVAL; we ignore this failure.
+ //
+ // N.B. read the man page for mlockall. MCL_CURRENT | MCL_ONFAULT
+ // pins ⊆ MCL_CURRENT, converging to just MCL_CURRENT as we fault
+ // in pages.
+
+ // CAP_IPC_LOCK required
+ mlockall(MCL_CURRENT | MCL_FUTURE | MCL_ONFAULT) && (errno != EINVAL)) {
+ PLOG(WARNING) << "mlockall failed ";
+ }
+
+ if (threadname) {
+ pthread_attr_t attr;
+
+ if (!pthread_attr_init(&attr)) {
+ sched_param param;
+
+ memset(¶m, 0, sizeof(param));
+ pthread_attr_setschedparam(&attr, ¶m);
+ pthread_attr_setschedpolicy(&attr, SCHED_BATCH);
+ if (!pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED)) {
+ pthread_t thread;
+ if (!pthread_create(&thread, &attr, llkThread, const_cast<char*>(threadname))) {
+ // wait a second for thread to start
+ for (auto retry = 50; retry && !llkRunning; --retry) {
+ ::usleep(20000);
+ }
+ logConfig = !llkRunning; // printed in llkd context?
+ } else {
+ LOG(ERROR) << "failed to spawn llkd thread";
+ }
+ } else {
+ LOG(ERROR) << "failed to detach llkd thread";
+ }
+ pthread_attr_destroy(&attr);
+ } else {
+ LOG(ERROR) << "failed to allocate attibutes for llkd thread";
+ }
+ }
+ } else {
+ LOG(DEBUG) << "[khungtaskd] left unconfigured";
+ }
+ if (logConfig) {
+ llkLogConfig();
+ }
+
+ return llkEnable;
+}
diff --git a/llkd/llkd.cpp b/llkd/llkd.cpp
new file mode 100644
index 0000000..f10253d
--- /dev/null
+++ b/llkd/llkd.cpp
@@ -0,0 +1,50 @@
+/*
+ * 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 "llkd.h"
+
+#include <sched.h>
+#include <unistd.h>
+
+#include <chrono>
+
+#include <android-base/logging.h>
+
+using namespace std::chrono;
+
+int main(int, char**) {
+ LOG(INFO) << "started";
+
+ bool enabled = llkInit();
+
+ // Would like this policy to be automatic as part of libllkd,
+ // but that would be presumptuous and bad side-effect.
+ struct sched_param param;
+ memset(¶m, 0, sizeof(param));
+ sched_setscheduler(0, SCHED_BATCH, ¶m);
+
+ while (true) {
+ if (enabled) {
+ ::usleep(duration_cast<microseconds>(llkCheck()).count());
+ } else {
+ ::pause();
+ }
+ }
+ // NOTREACHED
+
+ LOG(INFO) << "exiting";
+ return 0;
+}
diff --git a/llkd/llkd.rc b/llkd/llkd.rc
new file mode 100644
index 0000000..e538cdb
--- /dev/null
+++ b/llkd/llkd.rc
@@ -0,0 +1,49 @@
+# eng default for ro.llk.enable and ro.khungtask.enable
+on property:ro.debuggable=*
+ setprop llk.enable ${ro.llk.enable:-0}
+ setprop khungtask.enable ${ro.khungtask.enable:-0}
+
+on property:ro.debuggable=1
+ setprop llk.enable ${ro.llk.enable:-1}
+ setprop khungtask.enable ${ro.khungtask.enable:-1}
+
+on property:ro.llk.enable=eng
+ setprop llk.enable ${ro.debuggable:-0}
+
+on property:ro.khungtask.enable=eng
+ setprop khungtask.enable ${ro.debuggable:-0}
+
+on property:llk.enable=1
+ setprop llk.enable true
+
+on property:llk.enable=0
+ setprop llk.enable false
+
+on property:khungtask.enable=1
+ setprop khungtask.enable true
+
+on property:khungtask.enable=0
+ setprop khungtask.enable false
+
+# Configure [khungtaskd]
+on property:khungtask.enable=true
+ write /proc/sys/kernel/hung_task_timeout_secs ${ro.khungtask.timeout:-720}
+ write /proc/sys/kernel/hung_task_warnings 65535
+ write /proc/sys/kernel/hung_task_check_count 65535
+ write /proc/sys/kernel/hung_task_panic 1
+
+on property:khungtask.enable=false
+ write /proc/sys/kernel/hung_task_panic 0
+
+on property:llk.enable=true
+ start llkd
+
+service llkd /system/bin/llkd
+ class late_start
+ disabled
+ user llkd
+ group llkd readproc
+ capabilities KILL IPC_LOCK
+ file /dev/kmsg w
+ file /proc/sysrq-trigger w
+ writepid /dev/cpuset/system-background/tasks
diff --git a/llkd/tests/Android.bp b/llkd/tests/Android.bp
new file mode 100644
index 0000000..6dd5938
--- /dev/null
+++ b/llkd/tests/Android.bp
@@ -0,0 +1,41 @@
+// 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.
+
+cc_test {
+ name: "llkd_unit_test",
+
+ shared_libs: [
+ "libbase",
+ "liblog",
+ ],
+ header_libs: [
+ "llkd_headers",
+ ],
+
+ target: {
+ android: {
+ srcs: [
+ "llkd_test.cpp",
+ ],
+ },
+ },
+
+ cflags: [
+ "-Wall",
+ "-Wextra",
+ "-Werror",
+ ],
+
+ compile_multilib: "first",
+}
diff --git a/llkd/tests/llkd_test.cpp b/llkd/tests/llkd_test.cpp
new file mode 100644
index 0000000..3a15ff1
--- /dev/null
+++ b/llkd/tests/llkd_test.cpp
@@ -0,0 +1,287 @@
+/*
+ * 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 <signal.h>
+#include <stdint.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+#include <chrono>
+#include <iostream>
+#include <string>
+
+#include <android-base/properties.h>
+#include <gtest/gtest.h>
+#include <log/log_time.h> // for MS_PER_SEC and US_PER_SEC
+
+#include "llkd.h"
+
+using namespace std::chrono;
+using namespace std::chrono_literals;
+
+namespace {
+
+milliseconds GetUintProperty(const std::string& key, milliseconds def) {
+ return milliseconds(android::base::GetUintProperty(key, static_cast<uint64_t>(def.count()),
+ static_cast<uint64_t>(def.max().count())));
+}
+
+seconds GetUintProperty(const std::string& key, seconds def) {
+ return seconds(android::base::GetUintProperty(key, static_cast<uint64_t>(def.count()),
+ static_cast<uint64_t>(def.max().count())));
+}
+
+// GTEST_LOG_(WARNING) output is fugly, this has much less noise
+// ToDo: look into fixing googletest to produce output that matches style of
+// all the other status messages, and can switch off __line__ and
+// __function__ noise
+#define GTEST_LOG_WARNING std::cerr << "[ WARNING ] "
+#define GTEST_LOG_INFO std::cerr << "[ INFO ] "
+
+// Properties is _not_ a high performance ABI!
+void rest() {
+ usleep(200000);
+}
+
+void execute(const char* command) {
+ if (getuid() || system(command)) {
+ system((std::string("su root ") + command).c_str());
+ }
+}
+
+seconds llkdSleepPeriod(char state) {
+ auto default_eng = android::base::GetProperty(LLK_ENABLE_PROPERTY, "eng") == "eng";
+ auto default_enable = LLK_ENABLE_DEFAULT;
+ if (!LLK_ENABLE_DEFAULT && default_eng &&
+ android::base::GetBoolProperty("ro.debuggable", false)) {
+ default_enable = true;
+ }
+ default_enable = android::base::GetBoolProperty(LLK_ENABLE_PROPERTY, default_enable);
+ if (default_eng) {
+ GTEST_LOG_INFO << LLK_ENABLE_PROPERTY " defaults to \"eng\" thus "
+ << (default_enable ? "true" : "false") << "\n";
+ }
+ // Hail Mary hope is unconfigured.
+ if ((GetUintProperty(LLK_TIMEOUT_MS_PROPERTY, LLK_TIMEOUT_MS_DEFAULT) !=
+ duration_cast<milliseconds>(120s)) ||
+ (GetUintProperty(LLK_CHECK_MS_PROPERTY,
+ LLK_TIMEOUT_MS_DEFAULT / LLK_CHECKS_PER_TIMEOUT_DEFAULT) !=
+ duration_cast<milliseconds>(10s))) {
+ execute("stop llkd");
+ rest();
+ std::string setprop("setprop ");
+ execute((setprop + LLK_ENABLE_WRITEABLE_PROPERTY + " false").c_str());
+ rest();
+ execute((setprop + LLK_TIMEOUT_MS_PROPERTY + " 120000").c_str());
+ rest();
+ execute((setprop + KHT_TIMEOUT_PROPERTY + " 130").c_str());
+ rest();
+ execute((setprop + LLK_CHECK_MS_PROPERTY + " 10000").c_str());
+ rest();
+ execute((setprop + LLK_ENABLE_PROPERTY + " true").c_str());
+ rest();
+ execute((setprop + LLK_ENABLE_WRITEABLE_PROPERTY + " true").c_str());
+ rest();
+ }
+ default_enable = LLK_ENABLE_DEFAULT;
+ if (!LLK_ENABLE_DEFAULT && (android::base::GetProperty(LLK_ENABLE_PROPERTY, "eng") == "eng") &&
+ android::base::GetBoolProperty("ro.debuggable", false)) {
+ default_enable = true;
+ }
+ default_enable = android::base::GetBoolProperty(LLK_ENABLE_PROPERTY, default_enable);
+ if (default_enable) {
+ execute("start llkd");
+ rest();
+ GTEST_LOG_INFO << "llkd enabled\n";
+ } else {
+ GTEST_LOG_WARNING << "llkd disabled\n";
+ }
+
+ /* KISS follows llk_init() */
+ milliseconds llkTimeoutMs = LLK_TIMEOUT_MS_DEFAULT;
+ seconds khtTimeout = duration_cast<seconds>(
+ llkTimeoutMs * (1 + LLK_CHECKS_PER_TIMEOUT_DEFAULT) / LLK_CHECKS_PER_TIMEOUT_DEFAULT);
+ khtTimeout = GetUintProperty(KHT_TIMEOUT_PROPERTY, khtTimeout);
+ llkTimeoutMs =
+ khtTimeout * LLK_CHECKS_PER_TIMEOUT_DEFAULT / (1 + LLK_CHECKS_PER_TIMEOUT_DEFAULT);
+ llkTimeoutMs = GetUintProperty(LLK_TIMEOUT_MS_PROPERTY, llkTimeoutMs);
+ if (llkTimeoutMs < LLK_TIMEOUT_MS_MINIMUM) {
+ llkTimeoutMs = LLK_TIMEOUT_MS_MINIMUM;
+ }
+ milliseconds llkCheckMs = llkTimeoutMs / LLK_CHECKS_PER_TIMEOUT_DEFAULT;
+ auto timeout = GetUintProperty(
+ (state == 'Z') ? LLK_Z_TIMEOUT_MS_PROPERTY : LLK_D_TIMEOUT_MS_PROPERTY, llkTimeoutMs);
+ if (timeout < LLK_TIMEOUT_MS_MINIMUM) {
+ timeout = LLK_TIMEOUT_MS_MINIMUM;
+ }
+
+ if (llkCheckMs > timeout) {
+ llkCheckMs = timeout;
+ }
+ llkCheckMs = GetUintProperty(LLK_CHECK_MS_PROPERTY, llkCheckMs);
+ timeout += llkCheckMs;
+ auto sec = duration_cast<seconds>(timeout);
+ if (sec == 0s) {
+ ++sec;
+ } else if (sec > 59s) {
+ GTEST_LOG_WARNING << "llkd is configured for about " << duration_cast<minutes>(sec).count()
+ << " minutes to react\n";
+ }
+
+ // 33% margin for the test to naturally timeout waiting for llkd to respond
+ return (sec * 4 + 2s) / 3;
+}
+
+inline void waitForPid(pid_t child_pid) {
+ int wstatus;
+ ASSERT_LE(0, waitpid(child_pid, &wstatus, 0));
+ EXPECT_FALSE(WIFEXITED(wstatus)) << "[ INFO ] exit=" << WEXITSTATUS(wstatus);
+ ASSERT_TRUE(WIFSIGNALED(wstatus));
+ ASSERT_EQ(WTERMSIG(wstatus), SIGKILL);
+}
+
+bool checkKill(const char* reason) {
+ if (android::base::GetBoolProperty(LLK_KILLTEST_PROPERTY, LLK_KILLTEST_DEFAULT)) {
+ return false;
+ }
+ auto bootreason = android::base::GetProperty("sys.boot.reason", "nothing");
+ if (bootreason == reason) {
+ GTEST_LOG_INFO << "Expected test result confirmed " << reason << "\n";
+ return true;
+ }
+ GTEST_LOG_WARNING << "Expected test result is " << reason << "\n";
+
+ // apct adjustment if needed (set LLK_KILLTEST_PROPERTY to "off" to allow test)
+ //
+ // if (android::base::GetProperty(LLK_KILLTEST_PROPERTY, "") == "false") {
+ // GTEST_LOG_WARNING << "Bypassing test\n";
+ // return true;
+ // }
+
+ return false;
+}
+
+} // namespace
+
+// The tests that use this helper are to simulate processes stuck in 'D'
+// state that are experiencing forward scheduled progress. As such the
+// expectation is that llkd will _not_ perform any mitigations. The sleepfor
+// argument helps us set the amount of forward scheduler progress.
+static void llkd_driver_ABA(const microseconds sleepfor) {
+ const auto period = llkdSleepPeriod('D');
+ if (period <= sleepfor) {
+ GTEST_LOG_WARNING << "llkd configuration too short for "
+ << duration_cast<milliseconds>(sleepfor).count() << "ms work cycle\n";
+ return;
+ }
+
+ auto child_pid = fork();
+ ASSERT_LE(0, child_pid);
+ int wstatus;
+ if (!child_pid) {
+ auto ratio = period / sleepfor;
+ ASSERT_LT(0, ratio);
+ // vfork() parent is uninterruptable D state waiting for child to exec()
+ while (--ratio > 0) {
+ auto driver_pid = vfork();
+ ASSERT_LE(0, driver_pid);
+ if (driver_pid) { // parent
+ waitpid(driver_pid, &wstatus, 0);
+ if (!WIFEXITED(wstatus)) {
+ exit(42);
+ }
+ if (WEXITSTATUS(wstatus) != 42) {
+ exit(42);
+ }
+ } else {
+ usleep(sleepfor.count());
+ exit(42);
+ }
+ }
+ exit(0);
+ }
+ ASSERT_LE(0, waitpid(child_pid, &wstatus, 0));
+ EXPECT_TRUE(WIFEXITED(wstatus));
+ if (WIFEXITED(wstatus)) {
+ EXPECT_EQ(0, WEXITSTATUS(wstatus));
+ }
+ ASSERT_FALSE(WIFSIGNALED(wstatus)) << "[ INFO ] signo=" << WTERMSIG(wstatus);
+}
+
+TEST(llkd, driver_ABA_fast) {
+ llkd_driver_ABA(5ms);
+}
+
+TEST(llkd, driver_ABA_slow) {
+ llkd_driver_ABA(1s);
+}
+
+TEST(llkd, driver_ABA_glacial) {
+ llkd_driver_ABA(1min);
+}
+
+// Following tests must be last in this file to capture possible errant
+// kernel_panic mitigation failure.
+
+// The following tests simulate processes stick in 'Z' or 'D' state with
+// no forward scheduling progress, but interruptible. As such the expectation
+// is that llkd will perform kill mitigation and not progress to kernel_panic.
+
+TEST(llkd, zombie) {
+ if (checkKill("kernel_panic,sysrq,livelock,zombie")) {
+ return;
+ }
+
+ const auto period = llkdSleepPeriod('Z');
+
+ /* Create a Persistent Zombie Process */
+ pid_t child_pid = fork();
+ ASSERT_LE(0, child_pid);
+ if (!child_pid) {
+ auto zombie_pid = fork();
+ ASSERT_LE(0, zombie_pid);
+ if (!zombie_pid) {
+ sleep(1);
+ exit(0);
+ }
+ sleep(period.count());
+ exit(42);
+ }
+
+ waitForPid(child_pid);
+}
+
+TEST(llkd, driver) {
+ if (checkKill("kernel_panic,sysrq,livelock,driver")) {
+ return;
+ }
+
+ const auto period = llkdSleepPeriod('D');
+
+ /* Create a Persistent Device Process */
+ auto child_pid = fork();
+ ASSERT_LE(0, child_pid);
+ if (!child_pid) {
+ // vfork() parent is uninterruptable D state waiting for child to exec()
+ auto driver_pid = vfork();
+ ASSERT_LE(0, driver_pid);
+ sleep(period.count());
+ exit(driver_pid ? 42 : 0);
+ }
+
+ waitForPid(child_pid);
+}
diff --git a/lmkd/Android.bp b/lmkd/Android.bp
index 0474ff5..1369b8b 100644
--- a/lmkd/Android.bp
+++ b/lmkd/Android.bp
@@ -3,8 +3,8 @@
srcs: ["lmkd.c"],
shared_libs: [
- "liblog",
"libcutils",
+ "liblog",
],
static_libs: [
"libstatslogc",
diff --git a/lmkd/lmkd.c b/lmkd/lmkd.c
index 76344b9..c8416f9 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>
@@ -27,8 +29,8 @@
#include <sys/eventfd.h>
#include <sys/mman.h>
#include <sys/socket.h>
-#include <sys/types.h>
#include <sys/sysinfo.h>
+#include <sys/types.h>
#include <unistd.h>
#include <cutils/properties.h>
@@ -70,17 +72,18 @@
#define MEMINFO_PATH "/proc/meminfo"
#define LINE_MAX 128
+/* gid containing AID_SYSTEM required */
#define INKERNEL_MINFREE_PATH "/sys/module/lowmemorykiller/parameters/minfree"
#define INKERNEL_ADJ_PATH "/sys/module/lowmemorykiller/parameters/adj"
#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;
+static bool use_inkernel_interface = true;
static bool has_inkernel_module;
/* memory pressure levels */
@@ -417,24 +420,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) {
@@ -443,6 +454,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);
@@ -452,12 +465,21 @@
return;
}
+ /* gid containing AID_READPROC required */
+ /* CAP_SYS_RESOURCE required */
+ /* CAP_DAC_OVERRIDE required */
snprintf(path, sizeof(path), "/proc/%d/oom_score_adj", params.pid);
snprintf(val, sizeof(val), "%d", params.oomadj);
- writefilestring(path, val);
-
- if (use_inkernel_interface)
+ 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;
+ }
if (params.oomadj >= 900) {
soft_limit_mult = 0;
@@ -487,11 +509,18 @@
soft_limit_mult = 64;
}
- snprintf(path, sizeof(path),
- "/dev/memcg/apps/uid_%d/pid_%d/memory.soft_limit_in_bytes",
+ snprintf(path, sizeof(path), MEMCG_SYSFS_PATH "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) {
@@ -515,8 +544,9 @@
static void cmd_procremove(LMKD_CTRL_PACKET packet) {
struct lmk_procremove params;
- if (use_inkernel_interface)
+ if (use_inkernel_interface) {
return;
+ }
lmkd_pack_get_procremove(packet, ¶ms);
pid_remove(params.pid);
@@ -558,8 +588,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);
}
}
@@ -696,10 +726,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;
@@ -886,6 +916,7 @@
int total;
ssize_t ret;
+ /* gid containing AID_READPROC required */
snprintf(path, PATH_MAX, "/proc/%d/statm", pid);
fd = open(path, O_RDONLY | O_CLOEXEC);
if (fd == -1)
@@ -909,6 +940,7 @@
char *cp;
ssize_t ret;
+ /* gid containing AID_READPROC required */
snprintf(path, PATH_MAX, "/proc/%d/cmdline", pid);
fd = open(path, O_RDONLY | O_CLOEXEC);
if (fd == -1)
@@ -987,10 +1019,11 @@
TRACE_KILL_START(pid);
+ /* CAP_KILL required */
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);
@@ -1336,6 +1369,7 @@
int level_idx = (int)level;
const char *levelstr = level_name[level_idx];
+ /* gid containing AID_SYSTEM required */
mpfd = open(MEMCG_SYSFS_PATH "memory.pressure_level", O_RDONLY | O_CLOEXEC);
if (mpfd < 0) {
ALOGI("No kernel memory.pressure_level support (errno=%d)", errno);
@@ -1538,21 +1572,32 @@
statslog_init(&log_ctx, &enable_stats_log);
#endif
- // MCL_ONFAULT pins pages as they fault instead of loading
- // everything immediately all at once. (Which would be bad,
- // because as of this writing, we have a lot of mapped pages we
- // never use.) Old kernels will see MCL_ONFAULT and fail with
- // EINVAL; we ignore this failure.
- //
- // N.B. read the man page for mlockall. MCL_CURRENT | MCL_ONFAULT
- // pins ⊆ MCL_CURRENT, converging to just MCL_CURRENT as we fault
- // in pages.
- if (mlockall(MCL_CURRENT | MCL_FUTURE | MCL_ONFAULT) && errno != EINVAL)
- ALOGW("mlockall failed: errno=%d", errno);
+ if (!init()) {
+ if (!use_inkernel_interface) {
+ /*
+ * MCL_ONFAULT pins pages as they fault instead of loading
+ * everything immediately all at once. (Which would be bad,
+ * because as of this writing, we have a lot of mapped pages we
+ * never use.) Old kernels will see MCL_ONFAULT and fail with
+ * EINVAL; we ignore this failure.
+ *
+ * N.B. read the man page for mlockall. MCL_CURRENT | MCL_ONFAULT
+ * pins ⊆ MCL_CURRENT, converging to just MCL_CURRENT as we fault
+ * in pages.
+ */
+ /* CAP_IPC_LOCK required */
+ if (mlockall(MCL_CURRENT | MCL_FUTURE | MCL_ONFAULT) && (errno != EINVAL)) {
+ ALOGW("mlockall failed %s", strerror(errno));
+ }
- sched_setscheduler(0, SCHED_FIFO, ¶m);
- if (!init())
+ /* CAP_NICE required */
+ if (sched_setscheduler(0, SCHED_FIFO, ¶m)) {
+ ALOGW("set SCHED_FIFO failed %s", strerror(errno));
+ }
+ }
+
mainloop();
+ }
#ifdef LMKD_LOG_STATS
statslog_destroy(&log_ctx);
diff --git a/lmkd/lmkd.rc b/lmkd/lmkd.rc
index 3bb84ab..76b6055 100644
--- a/lmkd/lmkd.rc
+++ b/lmkd/lmkd.rc
@@ -1,6 +1,8 @@
service lmkd /system/bin/lmkd
class core
- group root readproc
+ user lmkd
+ group lmkd system readproc
+ capabilities DAC_OVERRIDE KILL IPC_LOCK SYS_NICE SYS_RESOURCE
critical
socket lmkd seqpacket 0660 system system
writepid /dev/cpuset/system-background/tasks
diff --git a/lmkd/tests/lmkd_test.cpp b/lmkd/tests/lmkd_test.cpp
index 4afaeb8..1996bae 100644
--- a/lmkd/tests/lmkd_test.cpp
+++ b/lmkd/tests/lmkd_test.cpp
@@ -215,6 +215,13 @@
pid_t pid;
uid_t uid = getuid();
+ // check if in-kernel LMK driver is present
+ if (!access(INKERNEL_MINFREE_PATH, W_OK)) {
+ GTEST_LOG_(INFO) << "Must not have kernel lowmemorykiller driver,"
+ << " terminating test";
+ return;
+ }
+
ASSERT_FALSE((sock = lmkd_connect()) < 0)
<< "Failed to connect to lmkd process, err=" << strerror(errno);
@@ -287,12 +294,6 @@
GTEST_LOG_(INFO) << "Must be userdebug build, terminating test";
return;
}
- // check if in-kernel LMK driver is present
- if (!access(INKERNEL_MINFREE_PATH, W_OK)) {
- GTEST_LOG_(INFO) << "Must not have kernel lowmemorykiller driver,"
- << " terminating test";
- return;
- }
// if respawned test process then run the test and exit (no analysis)
if (getenv(LMKDTEST_RESPAWN_FLAG) != NULL) {
diff --git a/logd/LogAudit.cpp b/logd/LogAudit.cpp
index 269db2f..27cd9a8 100755
--- a/logd/LogAudit.cpp
+++ b/logd/LogAudit.cpp
@@ -112,7 +112,7 @@
std::map<std::string, std::string> LogAudit::populateDenialMap() {
std::ifstream bug_file("/system/etc/selinux/selinux_denial_metadata");
std::string line;
- // allocate a map for the static map pointer in logParse to keep track of,
+ // allocate a map for the static map pointer in auditParse to keep track of,
// this function only runs once
std::map<std::string, std::string> denial_to_bug;
if (bug_file.good()) {
@@ -140,7 +140,8 @@
return "";
}
-void LogAudit::logParse(const std::string& string, std::string* bug_num) {
+void LogAudit::auditParse(const std::string& string, uid_t uid,
+ std::string* bug_num) {
if (!__android_log_is_debuggable()) {
bug_num->assign("");
return;
@@ -162,6 +163,11 @@
} else {
bug_num->assign("");
}
+
+ if (uid >= AID_APP_START && uid <= AID_APP_END) {
+ bug_num->append(" app=");
+ bug_num->append(android::uidToName(uid));
+ }
}
int LogAudit::logPrint(const char* fmt, ...) {
@@ -190,8 +196,27 @@
while ((cp = strstr(str, " "))) {
memmove(cp, cp + 1, strlen(cp + 1) + 1);
}
+ pid_t pid = getpid();
+ pid_t tid = gettid();
+ uid_t uid = AID_LOGD;
+ static const char pid_str[] = " pid=";
+ char* pidptr = strstr(str, pid_str);
+ if (pidptr && isdigit(pidptr[sizeof(pid_str) - 1])) {
+ cp = pidptr + sizeof(pid_str) - 1;
+ pid = 0;
+ while (isdigit(*cp)) {
+ pid = (pid * 10) + (*cp - '0');
+ ++cp;
+ }
+ tid = pid;
+ logbuf->wrlock();
+ uid = logbuf->pidToUid(pid);
+ logbuf->unlock();
+ memmove(pidptr, cp, strlen(cp) + 1);
+ }
+
bool info = strstr(str, " permissive=1") || strstr(str, " policy loaded ");
- static std::string bug_metadata;
+ static std::string denial_metadata;
if ((fdDmesg >= 0) && initialized) {
struct iovec iov[4];
static const char log_info[] = { KMSG_PRIORITY(LOG_INFO) };
@@ -228,8 +253,8 @@
last_info ? sizeof(log_info) : sizeof(log_warning);
iov[1].iov_base = last_str;
iov[1].iov_len = strlen(last_str);
- iov[2].iov_base = const_cast<char*>(bug_metadata.c_str());
- iov[2].iov_len = bug_metadata.length();
+ iov[2].iov_base = const_cast<char*>(denial_metadata.c_str());
+ iov[2].iov_len = denial_metadata.length();
if (count > 1) {
iov[3].iov_base = const_cast<char*>(resume);
iov[3].iov_len = strlen(resume);
@@ -249,14 +274,14 @@
last_info = info;
}
if (count == 0) {
- logParse(str, &bug_metadata);
+ auditParse(str, uid, &denial_metadata);
iov[0].iov_base = info ? const_cast<char*>(log_info)
: const_cast<char*>(log_warning);
iov[0].iov_len = info ? sizeof(log_info) : sizeof(log_warning);
iov[1].iov_base = str;
iov[1].iov_len = strlen(str);
- iov[2].iov_base = const_cast<char*>(bug_metadata.c_str());
- iov[2].iov_len = bug_metadata.length();
+ iov[2].iov_base = const_cast<char*>(denial_metadata.c_str());
+ iov[2].iov_len = denial_metadata.length();
iov[3].iov_base = const_cast<char*>(newline);
iov[3].iov_len = strlen(newline);
@@ -269,9 +294,6 @@
return 0;
}
- pid_t pid = getpid();
- pid_t tid = gettid();
- uid_t uid = AID_LOGD;
log_time now;
static const char audit_str[] = " audit(";
@@ -296,29 +318,13 @@
now = log_time(CLOCK_REALTIME);
}
- static const char pid_str[] = " pid=";
- char* pidptr = strstr(str, pid_str);
- if (pidptr && isdigit(pidptr[sizeof(pid_str) - 1])) {
- cp = pidptr + sizeof(pid_str) - 1;
- pid = 0;
- while (isdigit(*cp)) {
- pid = (pid * 10) + (*cp - '0');
- ++cp;
- }
- tid = pid;
- logbuf->wrlock();
- uid = logbuf->pidToUid(pid);
- logbuf->unlock();
- memmove(pidptr, cp, strlen(cp) + 1);
- }
-
// log to events
size_t str_len = strnlen(str, LOGGER_ENTRY_MAX_PAYLOAD);
if (((fdDmesg < 0) || !initialized) && !hasMetadata(str, str_len))
- logParse(str, &bug_metadata);
- str_len = (str_len + bug_metadata.length() <= LOGGER_ENTRY_MAX_PAYLOAD)
- ? str_len + bug_metadata.length()
+ auditParse(str, uid, &denial_metadata);
+ str_len = (str_len + denial_metadata.length() <= LOGGER_ENTRY_MAX_PAYLOAD)
+ ? str_len + denial_metadata.length()
: LOGGER_ENTRY_MAX_PAYLOAD;
size_t message_len = str_len + sizeof(android_log_event_string_t);
@@ -332,9 +338,9 @@
event->header.tag = htole32(AUDITD_LOG_TAG);
event->type = EVENT_TYPE_STRING;
event->length = htole32(str_len);
- memcpy(event->data, str, str_len - bug_metadata.length());
- memcpy(event->data + str_len - bug_metadata.length(),
- bug_metadata.c_str(), bug_metadata.length());
+ memcpy(event->data, str, str_len - denial_metadata.length());
+ memcpy(event->data + str_len - denial_metadata.length(),
+ denial_metadata.c_str(), denial_metadata.length());
rc = logbuf->log(
LOG_ID_EVENTS, now, uid, pid, tid, reinterpret_cast<char*>(event),
@@ -380,7 +386,8 @@
prefix_len = LOGGER_ENTRY_MAX_PAYLOAD;
}
size_t suffix_len = strnlen(ecomm, LOGGER_ENTRY_MAX_PAYLOAD - prefix_len);
- message_len = str_len + prefix_len + suffix_len + bug_metadata.length() + 2;
+ message_len =
+ str_len + prefix_len + suffix_len + denial_metadata.length() + 2;
if (main) { // begin scope for main buffer
char newstr[message_len];
@@ -390,7 +397,7 @@
strncpy(newstr + 1 + str_len, str, prefix_len);
strncpy(newstr + 1 + str_len + prefix_len, ecomm, suffix_len);
strncpy(newstr + 1 + str_len + prefix_len + suffix_len,
- bug_metadata.c_str(), bug_metadata.length());
+ denial_metadata.c_str(), denial_metadata.length());
rc = logbuf->log(LOG_ID_MAIN, now, uid, pid, tid, newstr,
(message_len <= USHRT_MAX) ? (unsigned short)message_len
diff --git a/logd/LogAudit.h b/logd/LogAudit.h
index 5904966..c3d7a3e 100644
--- a/logd/LogAudit.h
+++ b/logd/LogAudit.h
@@ -48,7 +48,7 @@
std::map<std::string, std::string> populateDenialMap();
std::string denialParse(const std::string& denial, char terminator,
const std::string& search_term);
- void logParse(const std::string& string, std::string* bug_num);
+ void auditParse(const std::string& string, uid_t uid, std::string* bug_num);
int logPrint(const char* fmt, ...)
__attribute__((__format__(__printf__, 2, 3)));
};
diff --git a/logd/main.cpp b/logd/main.cpp
index 4af0d21..606aa63 100644
--- a/logd/main.cpp
+++ b/logd/main.cpp
@@ -33,7 +33,6 @@
#include <syslog.h>
#include <unistd.h>
-#include <cstdbool>
#include <memory>
#include <android-base/macros.h>
diff --git a/logwrapper/Android.bp b/logwrapper/Android.bp
index 54506dc..d4ba4f4 100644
--- a/logwrapper/Android.bp
+++ b/logwrapper/Android.bp
@@ -41,14 +41,11 @@
defaults: ["logwrapper_common"],
}
-// Build vendor logwrapper.
-// TODO: Add vendor_available to "logwrapper" module and remove "logwrapper_vendor" module
-// when vendor_available is fully supported.
cc_binary {
name: "logwrapper_vendor",
+ defaults: ["logwrapper_common"],
stem: "logwrapper",
vendor: true,
- defaults: ["logwrapper_common"],
}
// ========================================================
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/mkbootimg/include/bootimg/bootimg.h b/mkbootimg/include/bootimg/bootimg.h
index 4311b46..406e208 100644
--- a/mkbootimg/include/bootimg/bootimg.h
+++ b/mkbootimg/include/bootimg/bootimg.h
@@ -1,37 +1,33 @@
-/* tools/mkbootimg/bootimg.h
-**
-** Copyright 2007, 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.
-*/
+/*
+ * Copyright (C) 2007 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.
+ */
+
+#pragma once
#include <stdint.h>
-#ifndef _BOOT_IMAGE_H_
-#define _BOOT_IMAGE_H_
-
#define BOOT_MAGIC "ANDROID!"
#define BOOT_MAGIC_SIZE 8
#define BOOT_NAME_SIZE 16
#define BOOT_ARGS_SIZE 512
#define BOOT_EXTRA_ARGS_SIZE 1024
-#define BOOT_HEADER_VERSION_ZERO 0
-/*
- * Bootloader expects the structure of boot_img_hdr with header version
- * BOOT_HEADER_VERSION_ZERO to be as follows:
- */
+// The bootloader expects the structure of boot_img_hdr with header
+// version 0 to be as follows:
struct boot_img_hdr_v0 {
+ // Must be BOOT_MAGIC.
uint8_t magic[BOOT_MAGIC_SIZE];
uint32_t kernel_size; /* size in bytes */
@@ -45,26 +41,36 @@
uint32_t tags_addr; /* physical addr for kernel tags */
uint32_t page_size; /* flash page size we assume */
- /*
- * version for the boot image header.
- */
+
+ // Version of the boot image header.
uint32_t header_version;
- /* operating system version and security patch level; for
- * version "A.B.C" and patch level "Y-M-D":
- * ver = A << 14 | B << 7 | C (7 bits for each of A, B, C)
- * lvl = ((Y - 2000) & 127) << 4 | M (7 bits for Y, 4 bits for M)
- * os_version = ver << 11 | lvl */
+ // Operating system version and security patch level.
+ // For version "A.B.C" and patch level "Y-M-D":
+ // (7 bits for each of A, B, C; 7 bits for (Y-2000), 4 bits for M)
+ // os_version = A[31:25] B[24:18] C[17:11] (Y-2000)[10:4] M[3:0]
uint32_t os_version;
+#if __cplusplus
+ void SetOsVersion(unsigned major, unsigned minor, unsigned patch) {
+ os_version &= ((1 << 11) - 1);
+ os_version |= (((major & 0x7f) << 25) | ((minor & 0x7f) << 18) | ((patch & 0x7f) << 11));
+ }
+
+ void SetOsPatchLevel(unsigned year, unsigned month) {
+ os_version &= ~((1 << 11) - 1);
+ os_version |= (((year - 2000) & 0x7f) << 4) | ((month & 0xf) << 0);
+ }
+#endif
+
uint8_t name[BOOT_NAME_SIZE]; /* asciiz product name */
uint8_t cmdline[BOOT_ARGS_SIZE];
uint32_t id[8]; /* timestamp / checksum / sha1 / etc */
- /* Supplemental command line data; kept here to maintain
- * binary compatibility with older versions of mkbootimg */
+ // Supplemental command line data; kept here to maintain
+ // binary compatibility with older versions of mkbootimg.
uint8_t extra_cmdline[BOOT_EXTRA_ARGS_SIZE];
} __attribute__((packed));
@@ -74,7 +80,7 @@
*/
typedef struct boot_img_hdr_v0 boot_img_hdr;
-/* When a boot header is of version BOOT_HEADER_VERSION_ZERO, the structure of boot image is as
+/* When a boot header is of version 0, the structure of boot image is as
* follows:
*
* +-----------------+
@@ -103,15 +109,13 @@
* else: jump to kernel_addr
*/
-#define BOOT_HEADER_VERSION_ONE 1
-
struct boot_img_hdr_v1 : public boot_img_hdr_v0 {
uint32_t recovery_dtbo_size; /* size in bytes for recovery DTBO image */
uint64_t recovery_dtbo_offset; /* physical load addr */
uint32_t header_size;
} __attribute__((packed));
-/* When the boot image header has a version of BOOT_HEADER_VERSION_ONE, the structure of the boot
+/* When the boot image header has a version of 1, the structure of the boot
* image is as follows:
*
* +-----------------+
@@ -142,23 +146,3 @@
* 7. if second_size != 0: jump to second_addr
* else: jump to kernel_addr
*/
-
-#if 0
-typedef struct ptentry ptentry;
-
-struct ptentry {
- char name[16]; /* asciiz partition name */
- unsigned start; /* starting block number */
- unsigned length; /* length in blocks */
- unsigned flags; /* set to zero */
-};
-
-/* MSM Partition Table ATAG
-**
-** length: 2 + 7 * n
-** atag: 0x4d534d70
-** <ptentry> x n
-*/
-#endif
-
-#endif
diff --git a/property_service/libpropertyinfoserializer/Android.bp b/property_service/libpropertyinfoserializer/Android.bp
index 72ae19a..3c4bdc3 100644
--- a/property_service/libpropertyinfoserializer/Android.bp
+++ b/property_service/libpropertyinfoserializer/Android.bp
@@ -35,4 +35,5 @@
"property_info_serializer_test.cpp",
],
static_libs: ["libpropertyinfoserializer"],
+ test_suites: ["device-tests"],
}
diff --git a/rootdir/etc/public.libraries.iot.txt b/rootdir/etc/public.libraries.iot.txt
new file mode 100644
index 0000000..ff0813d
--- /dev/null
+++ b/rootdir/etc/public.libraries.iot.txt
@@ -0,0 +1,27 @@
+# See https://android.googlesource.com/platform/ndk/+/master/docs/PlatformApis.md
+libandroid.so
+libandroidthings.so
+libaaudio.so
+libc.so
+libcamera2ndk.so
+libdl.so
+libEGL.so
+libGLESv1_CM.so
+libGLESv2.so
+libGLESv3.so
+libicui18n.so
+libicuuc.so
+libjnigraphics.so
+liblog.so
+libmediandk.so
+libm.so
+libnativewindow.so
+libneuralnetworks.so
+libOpenMAXAL.so
+libOpenSLES.so
+libRS.so
+libstdc++.so
+libsync.so
+libvulkan.so
+libwebviewchromium_plat_support.so
+libz.so
diff --git a/rootdir/init.rc b/rootdir/init.rc
index 4cc6693..f21490f 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -31,6 +31,9 @@
# root memory control cgroup, used by lmkd
mkdir /dev/memcg 0700 root system
mount cgroup none /dev/memcg nodev noexec nosuid memory
+ # memory.pressure_level used by lmkd
+ chown root system /dev/memcg/memory.pressure_level
+ chmod 0040 /dev/memcg/memory.pressure_level
# app mem cgroups, used by activity manager, lmkd and zygote
mkdir /dev/memcg/apps/ 0755 system system
# cgroup for system_server and surfaceflinger
@@ -429,6 +432,7 @@
mkdir /data/misc/radio 0770 system radio
mkdir /data/misc/sms 0770 system radio
mkdir /data/misc/carrierid 0770 system radio
+ mkdir /data/misc/apns 0770 system radio
mkdir /data/misc/zoneinfo 0775 system system
mkdir /data/misc/network_watchlist 0774 system system
mkdir /data/misc/textclassifier 0771 system system
@@ -519,6 +523,7 @@
mkdir /data/ss 0700 system system
mkdir /data/system 0775 system system
+ mkdir /data/system/dropbox 0700 system system
mkdir /data/system/heapdump 0700 system system
mkdir /data/system/users 0775 system system
diff --git a/shell_and_utilities/README.md b/shell_and_utilities/README.md
index c423c69..678b853 100644
--- a/shell_and_utilities/README.md
+++ b/shell_and_utilities/README.md
@@ -179,15 +179,41 @@
toybox: acpi base64 basename blockdev cal cat chcon chgrp chmod chown
chroot chrt cksum clear cmp comm cp cpio cut date df diff dirname dmesg
-dos2unix du echo env expand expr fallocate false file find flock free
+dos2unix du echo env expand expr fallocate false file find flock fmt free
getenforce groups gunzip gzip head hostname hwclock id ifconfig inotifyd
-insmod ionice iorenice kill killall ln load\_policy log logname losetup
-ls lsmod lsof lspci lsusb md5sum microcom mkdir mkfifo mknod mkswap
-mktemp modinfo modprobe more mount mountpoint mv netstat nice nl nohup
-od paste patch pgrep pidof pkill pmap printenv printf ps pwd readlink
-realpath renice restorecon rm rmdir rmmod runcon sed sendevent seq
-setenforce setprop setsid sha1sum sha224sum sha256sum sha384sum
-sha512sum sleep sort split start stat stop strings swapoff swapon sync
-sysctl tac tail tar taskset tee time timeout top touch tr true truncate
-tty ulimit umount uname uniq unix2dos uptime usleep uudecode uuencode
-vmstat wc which whoami xargs xxd yes zcat
+insmod ionice iorenice kill killall ln load\_policy log logname losetup ls
+lsmod lsof lspci lsusb md5sum microcom mkdir mkfifo mknod mkswap mktemp
+modinfo modprobe more mount mountpoint mv netstat nice nl nohup od paste
+patch pgrep pidof pkill pmap printenv printf ps pwd readlink realpath
+renice restorecon rm rmdir rmmod runcon sed sendevent seq setenforce
+setprop setsid sha1sum sha224sum sha256sum sha384sum sha512sum sleep
+sort split start stat stop strings stty swapoff swapon sync sysctl tac
+tail tar taskset tee time timeout top touch tr true truncate tty ulimit
+umount uname uniq unix2dos uptime usleep uudecode uuencode vmstat wc
+which whoami xargs xxd yes zcat
+
+Android Q
+---------
+
+bzip2: bzcat bzip2 bunzip2
+
+one-true-awk: awk
+
+PCRE: egrep fgrep grep
+
+toolbox: getevent getprop newfs\_msdos
+
+toybox: acpi base64 basename blockdev cal cat chcon chgrp chmod chown
+chroot chrt cksum clear cmp comm cp cpio cut date dd df diff dirname
+dmesg dos2unix du echo env expand expr fallocate false file find flock
+fmt free getenforce groups gunzip gzip head hostname hwclock id ifconfig
+inotifyd insmod ionice iorenice kill killall ln load\_policy log logname
+losetup ls lsmod lsof lspci lsusb md5sum microcom mkdir mkfifo mknod
+mkswap mktemp modinfo modprobe more mount mountpoint mv nc netcat netstat
+nice nl nohup nsenter od paste patch pgrep pidof pkill pmap printenv
+printf ps pwd readlink realpath renice restorecon rm rmdir rmmod runcon
+sed sendevent seq setenforce setprop setsid sha1sum sha224sum sha256sum
+sha384sum sha512sum sleep sort split start stat stop strings stty swapoff
+swapon sync sysctl tac tail tar taskset tee time timeout top touch tr
+true truncate tty ulimit umount uname uniq unix2dos unshare uptime usleep
+uudecode uuencode vmstat wc which whoami xargs xxd yes zcat
diff --git a/storaged/OWNERS b/storaged/OWNERS
index 7445270..d033f00 100644
--- a/storaged/OWNERS
+++ b/storaged/OWNERS
@@ -1 +1,2 @@
-jinqian@google.com
+salyzyn@google.com
+dvander@google.com
diff --git a/storaged/main.cpp b/storaged/main.cpp
index b3f1281..3817fb5 100644
--- a/storaged/main.cpp
+++ b/storaged/main.cpp
@@ -21,9 +21,6 @@
#include <getopt.h>
#include <pthread.h>
#include <stdio.h>
-#include <sys/capability.h>
-#include <sys/prctl.h>
-#include <sys/resource.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <vector>
diff --git a/toolbox/Android.bp b/toolbox/Android.bp
index ddd95b2..077f542 100644
--- a/toolbox/Android.bp
+++ b/toolbox/Android.bp
@@ -5,32 +5,8 @@
"-Werror",
"-Wno-unused-parameter",
"-Wno-unused-const-variable",
- "-include bsd-compatibility.h",
"-D_FILE_OFFSET_BITS=64",
- ],
- local_include_dirs: ["upstream-netbsd/include/"],
-}
-
-cc_library_static {
- name: "libtoolbox_dd",
- defaults: ["toolbox_defaults"],
- vendor_available: true,
- srcs: [
- "upstream-netbsd/bin/dd/args.c",
- "upstream-netbsd/bin/dd/conv.c",
- "upstream-netbsd/bin/dd/dd.c",
- "upstream-netbsd/bin/dd/dd_hostops.c",
- "upstream-netbsd/bin/dd/misc.c",
- "upstream-netbsd/bin/dd/position.c",
- "upstream-netbsd/lib/libc/gen/getbsize.c",
- "upstream-netbsd/lib/libc/gen/humanize_number.c",
- "upstream-netbsd/lib/libc/stdlib/strsuftoll.c",
- "upstream-netbsd/lib/libc/string/swab.c",
- "upstream-netbsd/lib/libutil/raise_default_signal.c",
- ],
- cflags: [
- "-Dmain=dd_main",
- "-DNO_CONV",
+ "-DWITHOUT_NLS",
],
}
@@ -55,15 +31,12 @@
generated_headers: [
"toolbox_input_labels",
],
- whole_static_libs: ["libtoolbox_dd"],
shared_libs: [
"libbase",
- "libcutils",
],
static_libs: ["libpropertyinfoparser"],
symlinks: [
- "dd",
"getevent",
"getprop",
"newfs_msdos",
@@ -89,38 +62,9 @@
srcs: ["r.c"],
}
-// We build BSD grep separately, so it can provide egrep and fgrep too.
-cc_defaults {
- name: "grep_common",
+cc_binary_host {
+ name: "newfs_msdos",
defaults: ["toolbox_defaults"],
- srcs: [
- "upstream-netbsd/usr.bin/grep/fastgrep.c",
- "upstream-netbsd/usr.bin/grep/file.c",
- "upstream-netbsd/usr.bin/grep/grep.c",
- "upstream-netbsd/usr.bin/grep/queue.c",
- "upstream-netbsd/usr.bin/grep/util.c",
- ],
- symlinks: [
- "egrep",
- "fgrep",
- ],
-
- sanitize: {
- integer_overflow: false,
- },
-}
-
-cc_binary {
- name: "grep",
- defaults: ["grep_common"],
-}
-
-// Build vendor grep.
-// TODO: Add vendor_available to "grep" module and remove "grep_vendor" module
-// when vendor_available is fully supported.
-cc_binary {
- name: "grep_vendor",
- stem: "grep",
- vendor: true,
- defaults: ["grep_common"],
+ srcs: ["newfs_msdos.c"],
+ cflags: ["-Dnewfs_msdos_main=main"]
}
diff --git a/toolbox/bsd-compatibility.h b/toolbox/bsd-compatibility.h
deleted file mode 100644
index 7c3ddd4..0000000
--- a/toolbox/bsd-compatibility.h
+++ /dev/null
@@ -1,84 +0,0 @@
-/*
- * Copyright (C) 2014, The Android Open Source Project
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
- * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
- * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
- * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
- * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
- * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
- * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#include <stdbool.h>
-#include <sys/types.h>
-
-/* We want chown to support user.group as well as user:group. */
-#define SUPPORT_DOT
-
-/* We don't localize /system/bin! */
-#define WITHOUT_NLS
-
-// NetBSD uses _DIAGASSERT to null-check arguments and the like.
-#include <assert.h>
-#define _DIAGASSERT(e) ((e) ? (void) 0 : __assert2(__FILE__, __LINE__, __func__, #e))
-
-// TODO: update our <sys/cdefs.h> to support this properly.
-#define __type_fit(t, a) (0 == 0)
-
-// TODO: should this be in our <sys/cdefs.h>?
-#define __arraycount(a) (sizeof(a) / sizeof((a)[0]))
-
-// This at least matches GNU dd(1) behavior.
-#define SIGINFO SIGUSR1
-
-#define S_ISWHT(x) false
-
-__BEGIN_DECLS
-
-/* From NetBSD <stdlib.h>. */
-#define HN_DECIMAL 0x01
-#define HN_NOSPACE 0x02
-#define HN_B 0x04
-#define HN_DIVISOR_1000 0x08
-#define HN_GETSCALE 0x10
-#define HN_AUTOSCALE 0x20
-int humanize_number(char *, size_t, int64_t, const char *, int, int);
-int dehumanize_number(const char *, int64_t *);
-char *getbsize(int *, long *);
-long long strsuftoll(const char *, const char *, long long, long long);
-long long strsuftollx(const char *, const char *, long long, long long,
- char *, size_t);
-
-/* From NetBSD <string.h>. */
-void strmode(mode_t, char*);
-
-/* From NetBSD <sys/param.h>. */
-#define MAXBSIZE 65536
-
-/* From NetBSD <sys/stat.h>. */
-#define DEFFILEMODE (S_IRUSR | S_IWUSR)
-
-/* From NetBSD <unistd.h>. */
-void swab(const void * __restrict, void * __restrict, ssize_t);
-
-/* From NetBSD <util.h>. */
-int raise_default_signal(int);
-
-__END_DECLS
diff --git a/toolbox/newfs_msdos.c b/toolbox/newfs_msdos.c
index d7047e2..5fc8b02 100644
--- a/toolbox/newfs_msdos.c
+++ b/toolbox/newfs_msdos.c
@@ -32,15 +32,17 @@
#include <sys/param.h>
-#ifndef ANDROID
+#ifdef __APPLE__
+#elif defined(ANDROID)
+#include <linux/fs.h>
+#include <linux/hdreg.h>
+#include <stdarg.h>
+#include <sys/ioctl.h>
+#else
#include <sys/fdcio.h>
#include <sys/disk.h>
#include <sys/disklabel.h>
#include <sys/mount.h>
-#else
-#include <stdarg.h>
-#include <linux/fs.h>
-#include <linux/hdreg.h>
#endif
#include <sys/stat.h>
@@ -58,6 +60,10 @@
#include <time.h>
#include <unistd.h>
+#ifndef __unused
+#define __unused __attribute__((__unused__))
+#endif
+
#define MAXU16 0xffff /* maximum unsigned 16-bit quantity */
#define BPN 4 /* bits per nibble */
#define NPB 2 /* nibbles per byte */
@@ -794,7 +800,10 @@
* Get disk slice, partition, and geometry information.
*/
-#ifdef ANDROID
+#ifdef __APPLE__
+static void getdiskinfo(__unused int fd, __unused const char* fname, __unused const char* dtype,
+ __unused int oflag, __unused struct bpb* bpb) {}
+#elif ANDROID
static void getdiskinfo(int fd, const char *fname, const char *dtype,
__unused int oflag,struct bpb *bpb)
{
diff --git a/toolbox/tools.h b/toolbox/tools.h
index 505f528..3d4bc3e 100644
--- a/toolbox/tools.h
+++ b/toolbox/tools.h
@@ -1,4 +1,3 @@
-TOOL(dd)
TOOL(getevent)
TOOL(getprop)
TOOL(newfs_msdos)
diff --git a/toolbox/upstream-netbsd/bin/dd/args.c b/toolbox/upstream-netbsd/bin/dd/args.c
deleted file mode 100644
index 207e300..0000000
--- a/toolbox/upstream-netbsd/bin/dd/args.c
+++ /dev/null
@@ -1,391 +0,0 @@
-/* $NetBSD: args.c,v 1.38 2013/07/17 12:55:48 christos Exp $ */
-
-/*-
- * Copyright (c) 1991, 1993, 1994
- * The Regents of the University of California. All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Keith Muller of the University of California, San Diego and Lance
- * Visser of Convex Computer Corporation.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the University nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#include <sys/cdefs.h>
-#ifndef lint
-#if 0
-static char sccsid[] = "@(#)args.c 8.3 (Berkeley) 4/2/94";
-#else
-__RCSID("$NetBSD: args.c,v 1.38 2013/07/17 12:55:48 christos Exp $");
-#endif
-#endif /* not lint */
-
-#include <sys/types.h>
-#include <sys/time.h>
-
-#include <err.h>
-#include <errno.h>
-#include <limits.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include "dd.h"
-#include "extern.h"
-
-static int c_arg(const void *, const void *);
-
-#ifdef NO_MSGFMT
-static void f_msgfmt(char *) __dead;
-#else
-static void f_msgfmt(char *);
-#endif /* NO_MSGFMT */
-
-#ifdef NO_CONV
-static void f_conv(char *) __dead;
-#else
-static void f_conv(char *);
-static int c_conv(const void *, const void *);
-#endif /* NO_CONV */
-
-static void f_bs(char *);
-static void f_cbs(char *);
-static void f_count(char *);
-static void f_files(char *);
-static void f_ibs(char *);
-static void f_if(char *);
-static void f_obs(char *);
-static void f_of(char *);
-static void f_seek(char *);
-static void f_skip(char *);
-static void f_progress(char *);
-
-static const struct arg {
- const char *name;
- void (*f)(char *);
- u_int set, noset;
-} args[] = {
- /* the array needs to be sorted by the first column so
- bsearch() can be used to find commands quickly */
- { "bs", f_bs, C_BS, C_BS|C_IBS|C_OBS|C_OSYNC },
- { "cbs", f_cbs, C_CBS, C_CBS },
- { "conv", f_conv, 0, 0 },
- { "count", f_count, C_COUNT, C_COUNT },
- { "files", f_files, C_FILES, C_FILES },
- { "ibs", f_ibs, C_IBS, C_BS|C_IBS },
- { "if", f_if, C_IF, C_IF },
- { "iseek", f_skip, C_SKIP, C_SKIP },
- { "msgfmt", f_msgfmt, 0, 0 },
- { "obs", f_obs, C_OBS, C_BS|C_OBS },
- { "of", f_of, C_OF, C_OF },
- { "oseek", f_seek, C_SEEK, C_SEEK },
- { "progress", f_progress, 0, 0 },
- { "seek", f_seek, C_SEEK, C_SEEK },
- { "skip", f_skip, C_SKIP, C_SKIP },
-};
-
-/*
- * args -- parse JCL syntax of dd.
- */
-void
-jcl(char **argv)
-{
- struct arg *ap, tmp;
- char *oper, *arg;
-
- in.dbsz = out.dbsz = 512;
-
- while ((oper = *++argv) != NULL) {
- if ((oper = strdup(oper)) == NULL) {
- errx(EXIT_FAILURE,
- "unable to allocate space for the argument %s",
- *argv);
- /* NOTREACHED */
- }
- if ((arg = strchr(oper, '=')) == NULL) {
- errx(EXIT_FAILURE, "unknown operand %s", oper);
- /* NOTREACHED */
- }
- *arg++ = '\0';
- if (!*arg) {
- errx(EXIT_FAILURE, "no value specified for %s", oper);
- /* NOTREACHED */
- }
- tmp.name = oper;
- if (!(ap = bsearch(&tmp, args,
- __arraycount(args), sizeof(*args), c_arg))) {
- errx(EXIT_FAILURE, "unknown operand %s", tmp.name);
- /* NOTREACHED */
- }
- if (ddflags & ap->noset) {
- errx(EXIT_FAILURE,
- "%s: illegal argument combination or already set",
- tmp.name);
- /* NOTREACHED */
- }
- ddflags |= ap->set;
- ap->f(arg);
- }
-
- /* Final sanity checks. */
-
- if (ddflags & C_BS) {
- /*
- * Bs is turned off by any conversion -- we assume the user
- * just wanted to set both the input and output block sizes
- * and didn't want the bs semantics, so we don't warn.
- */
- if (ddflags & (C_BLOCK | C_LCASE | C_SWAB | C_UCASE |
- C_UNBLOCK | C_OSYNC | C_ASCII | C_EBCDIC | C_SPARSE)) {
- ddflags &= ~C_BS;
- ddflags |= C_IBS|C_OBS;
- }
-
- /* Bs supersedes ibs and obs. */
- if (ddflags & C_BS && ddflags & (C_IBS|C_OBS))
- warnx("bs supersedes ibs and obs");
- }
-
- /*
- * Ascii/ebcdic and cbs implies block/unblock.
- * Block/unblock requires cbs and vice-versa.
- */
- if (ddflags & (C_BLOCK|C_UNBLOCK)) {
- if (!(ddflags & C_CBS)) {
- errx(EXIT_FAILURE, "record operations require cbs");
- /* NOTREACHED */
- }
- cfunc = ddflags & C_BLOCK ? block : unblock;
- } else if (ddflags & C_CBS) {
- if (ddflags & (C_ASCII|C_EBCDIC)) {
- if (ddflags & C_ASCII) {
- ddflags |= C_UNBLOCK;
- cfunc = unblock;
- } else {
- ddflags |= C_BLOCK;
- cfunc = block;
- }
- } else {
- errx(EXIT_FAILURE,
- "cbs meaningless if not doing record operations");
- /* NOTREACHED */
- }
- } else
- cfunc = def;
-
- /* Read, write and seek calls take off_t as arguments.
- *
- * The following check is not done because an off_t is a quad
- * for current NetBSD implementations.
- *
- * if (in.offset > INT_MAX/in.dbsz || out.offset > INT_MAX/out.dbsz)
- * errx(1, "seek offsets cannot be larger than %d", INT_MAX);
- */
-}
-
-static int
-c_arg(const void *a, const void *b)
-{
-
- return (strcmp(((const struct arg *)a)->name,
- ((const struct arg *)b)->name));
-}
-
-static void
-f_bs(char *arg)
-{
-
- in.dbsz = out.dbsz = strsuftoll("block size", arg, 1, UINT_MAX);
-}
-
-static void
-f_cbs(char *arg)
-{
-
- cbsz = strsuftoll("conversion record size", arg, 1, UINT_MAX);
-}
-
-static void
-f_count(char *arg)
-{
-
- cpy_cnt = strsuftoll("block count", arg, 0, LLONG_MAX);
- if (!cpy_cnt)
- terminate(0);
-}
-
-static void
-f_files(char *arg)
-{
-
- files_cnt = (u_int)strsuftoll("file count", arg, 0, UINT_MAX);
- if (!files_cnt)
- terminate(0);
-}
-
-static void
-f_ibs(char *arg)
-{
-
- if (!(ddflags & C_BS))
- in.dbsz = strsuftoll("input block size", arg, 1, UINT_MAX);
-}
-
-static void
-f_if(char *arg)
-{
-
- in.name = arg;
-}
-
-#ifdef NO_MSGFMT
-/* Build a small version (i.e. for a ramdisk root) */
-static void
-f_msgfmt(char *arg)
-{
-
- errx(EXIT_FAILURE, "msgfmt option disabled");
- /* NOTREACHED */
-}
-#else /* NO_MSGFMT */
-static void
-f_msgfmt(char *arg)
-{
-
- /*
- * If the format string is not valid, dd_write_msg() will print
- * an error and exit.
- */
- dd_write_msg(arg, 0);
-
- msgfmt = arg;
-}
-#endif /* NO_MSGFMT */
-
-static void
-f_obs(char *arg)
-{
-
- if (!(ddflags & C_BS))
- out.dbsz = strsuftoll("output block size", arg, 1, UINT_MAX);
-}
-
-static void
-f_of(char *arg)
-{
-
- out.name = arg;
-}
-
-static void
-f_seek(char *arg)
-{
-
- out.offset = strsuftoll("seek blocks", arg, 0, LLONG_MAX);
-}
-
-static void
-f_skip(char *arg)
-{
-
- in.offset = strsuftoll("skip blocks", arg, 0, LLONG_MAX);
-}
-
-static void
-f_progress(char *arg)
-{
-
- progress = strsuftoll("progress blocks", arg, 0, LLONG_MAX);
-}
-
-#ifdef NO_CONV
-/* Build a small version (i.e. for a ramdisk root) */
-static void
-f_conv(char *arg)
-{
-
- errx(EXIT_FAILURE, "conv option disabled");
- /* NOTREACHED */
-}
-#else /* NO_CONV */
-
-static const struct conv {
- const char *name;
- u_int set, noset;
- const u_char *ctab;
-} clist[] = {
- { "ascii", C_ASCII, C_EBCDIC, e2a_POSIX },
- { "block", C_BLOCK, C_UNBLOCK, NULL },
- { "ebcdic", C_EBCDIC, C_ASCII, a2e_POSIX },
- { "ibm", C_EBCDIC, C_ASCII, a2ibm_POSIX },
- { "lcase", C_LCASE, C_UCASE, NULL },
- { "noerror", C_NOERROR, 0, NULL },
- { "notrunc", C_NOTRUNC, 0, NULL },
- { "oldascii", C_ASCII, C_EBCDIC, e2a_32V },
- { "oldebcdic", C_EBCDIC, C_ASCII, a2e_32V },
- { "oldibm", C_EBCDIC, C_ASCII, a2ibm_32V },
- { "osync", C_OSYNC, C_BS, NULL },
- { "sparse", C_SPARSE, 0, NULL },
- { "swab", C_SWAB, 0, NULL },
- { "sync", C_SYNC, 0, NULL },
- { "ucase", C_UCASE, C_LCASE, NULL },
- { "unblock", C_UNBLOCK, C_BLOCK, NULL },
- /* If you add items to this table, be sure to add the
- * conversions to the C_BS check in the jcl routine above.
- */
-};
-
-static void
-f_conv(char *arg)
-{
- struct conv *cp, tmp;
-
- while (arg != NULL) {
- tmp.name = strsep(&arg, ",");
- if (!(cp = bsearch(&tmp, clist,
- __arraycount(clist), sizeof(*clist), c_conv))) {
- errx(EXIT_FAILURE, "unknown conversion %s", tmp.name);
- /* NOTREACHED */
- }
- if (ddflags & cp->noset) {
- errx(EXIT_FAILURE,
- "%s: illegal conversion combination", tmp.name);
- /* NOTREACHED */
- }
- ddflags |= cp->set;
- if (cp->ctab)
- ctab = cp->ctab;
- }
-}
-
-static int
-c_conv(const void *a, const void *b)
-{
-
- return (strcmp(((const struct conv *)a)->name,
- ((const struct conv *)b)->name));
-}
-
-#endif /* NO_CONV */
diff --git a/toolbox/upstream-netbsd/bin/dd/conv.c b/toolbox/upstream-netbsd/bin/dd/conv.c
deleted file mode 100644
index d4a8a09..0000000
--- a/toolbox/upstream-netbsd/bin/dd/conv.c
+++ /dev/null
@@ -1,283 +0,0 @@
-/* $NetBSD: conv.c,v 1.17 2003/08/07 09:05:10 agc Exp $ */
-
-/*-
- * Copyright (c) 1991, 1993, 1994
- * The Regents of the University of California. All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Keith Muller of the University of California, San Diego and Lance
- * Visser of Convex Computer Corporation.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the University nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#include <sys/cdefs.h>
-#ifndef lint
-#if 0
-static char sccsid[] = "@(#)conv.c 8.3 (Berkeley) 4/2/94";
-#else
-__RCSID("$NetBSD: conv.c,v 1.17 2003/08/07 09:05:10 agc Exp $");
-#endif
-#endif /* not lint */
-
-#include <sys/param.h>
-#include <sys/time.h>
-
-#include <err.h>
-#include <string.h>
-#include <stdlib.h>
-
-#include "dd.h"
-#include "extern.h"
-
-/*
- * def --
- * Copy input to output. Input is buffered until reaches obs, and then
- * output until less than obs remains. Only a single buffer is used.
- * Worst case buffer calculation is (ibs + obs - 1).
- */
-void
-def(void)
-{
- uint64_t cnt;
- u_char *inp;
- const u_char *t;
-
- if ((t = ctab) != NULL)
- for (inp = in.dbp - (cnt = in.dbrcnt); cnt--; ++inp)
- *inp = t[*inp];
-
- /* Make the output buffer look right. */
- out.dbp = in.dbp;
- out.dbcnt = in.dbcnt;
-
- if (in.dbcnt >= out.dbsz) {
- /* If the output buffer is full, write it. */
- dd_out(0);
-
- /*
- * Ddout copies the leftover output to the beginning of
- * the buffer and resets the output buffer. Reset the
- * input buffer to match it.
- */
- in.dbp = out.dbp;
- in.dbcnt = out.dbcnt;
- }
-}
-
-void
-def_close(void)
-{
-
- /* Just update the count, everything is already in the buffer. */
- if (in.dbcnt)
- out.dbcnt = in.dbcnt;
-}
-
-#ifdef NO_CONV
-/* Build a smaller version (i.e. for a miniroot) */
-/* These can not be called, but just in case... */
-static const char no_block[] = "unblock and -DNO_CONV?";
-void block(void) { errx(EXIT_FAILURE, "%s", no_block + 2); }
-void block_close(void) { errx(EXIT_FAILURE, "%s", no_block + 2); }
-void unblock(void) { errx(EXIT_FAILURE, "%s", no_block); }
-void unblock_close(void) { errx(EXIT_FAILURE, "%s", no_block); }
-#else /* NO_CONV */
-
-/*
- * Copy variable length newline terminated records with a max size cbsz
- * bytes to output. Records less than cbs are padded with spaces.
- *
- * max in buffer: MAX(ibs, cbsz)
- * max out buffer: obs + cbsz
- */
-void
-block(void)
-{
- static int intrunc;
- int ch = 0; /* pacify gcc */
- uint64_t cnt, maxlen;
- u_char *inp, *outp;
- const u_char *t;
-
- /*
- * Record truncation can cross block boundaries. If currently in a
- * truncation state, keep tossing characters until reach a newline.
- * Start at the beginning of the buffer, as the input buffer is always
- * left empty.
- */
- if (intrunc) {
- for (inp = in.db, cnt = in.dbrcnt;
- cnt && *inp++ != '\n'; --cnt);
- if (!cnt) {
- in.dbcnt = 0;
- in.dbp = in.db;
- return;
- }
- intrunc = 0;
- /* Adjust the input buffer numbers. */
- in.dbcnt = cnt - 1;
- in.dbp = inp + cnt - 1;
- }
-
- /*
- * Copy records (max cbsz size chunks) into the output buffer. The
- * translation is done as we copy into the output buffer.
- */
- for (inp = in.dbp - in.dbcnt, outp = out.dbp; in.dbcnt;) {
- maxlen = MIN(cbsz, in.dbcnt);
- if ((t = ctab) != NULL)
- for (cnt = 0;
- cnt < maxlen && (ch = *inp++) != '\n'; ++cnt)
- *outp++ = t[ch];
- else
- for (cnt = 0;
- cnt < maxlen && (ch = *inp++) != '\n'; ++cnt)
- *outp++ = ch;
- /*
- * Check for short record without a newline. Reassemble the
- * input block.
- */
- if (ch != '\n' && in.dbcnt < cbsz) {
- (void)memmove(in.db, in.dbp - in.dbcnt, in.dbcnt);
- break;
- }
-
- /* Adjust the input buffer numbers. */
- in.dbcnt -= cnt;
- if (ch == '\n')
- --in.dbcnt;
-
- /* Pad short records with spaces. */
- if (cnt < cbsz)
- (void)memset(outp, ctab ? ctab[' '] : ' ', cbsz - cnt);
- else {
- /*
- * If the next character wouldn't have ended the
- * block, it's a truncation.
- */
- if (!in.dbcnt || *inp != '\n')
- ++st.trunc;
-
- /* Toss characters to a newline. */
- for (; in.dbcnt && *inp++ != '\n'; --in.dbcnt);
- if (!in.dbcnt)
- intrunc = 1;
- else
- --in.dbcnt;
- }
-
- /* Adjust output buffer numbers. */
- out.dbp += cbsz;
- if ((out.dbcnt += cbsz) >= out.dbsz)
- dd_out(0);
- outp = out.dbp;
- }
- in.dbp = in.db + in.dbcnt;
-}
-
-void
-block_close(void)
-{
-
- /*
- * Copy any remaining data into the output buffer and pad to a record.
- * Don't worry about truncation or translation, the input buffer is
- * always empty when truncating, and no characters have been added for
- * translation. The bottom line is that anything left in the input
- * buffer is a truncated record. Anything left in the output buffer
- * just wasn't big enough.
- */
- if (in.dbcnt) {
- ++st.trunc;
- (void)memmove(out.dbp, in.dbp - in.dbcnt, in.dbcnt);
- (void)memset(out.dbp + in.dbcnt,
- ctab ? ctab[' '] : ' ', cbsz - in.dbcnt);
- out.dbcnt += cbsz;
- }
-}
-
-/*
- * Convert fixed length (cbsz) records to variable length. Deletes any
- * trailing blanks and appends a newline.
- *
- * max in buffer: MAX(ibs, cbsz) + cbsz
- * max out buffer: obs + cbsz
- */
-void
-unblock(void)
-{
- uint64_t cnt;
- u_char *inp;
- const u_char *t;
-
- /* Translation and case conversion. */
- if ((t = ctab) != NULL)
- for (cnt = in.dbrcnt, inp = in.dbp - 1; cnt--; inp--)
- *inp = t[*inp];
- /*
- * Copy records (max cbsz size chunks) into the output buffer. The
- * translation has to already be done or we might not recognize the
- * spaces.
- */
- for (inp = in.db; in.dbcnt >= cbsz; inp += cbsz, in.dbcnt -= cbsz) {
- for (t = inp + cbsz - 1; t >= inp && *t == ' '; --t);
- if (t >= inp) {
- cnt = t - inp + 1;
- (void)memmove(out.dbp, inp, cnt);
- out.dbp += cnt;
- out.dbcnt += cnt;
- }
- ++out.dbcnt;
- *out.dbp++ = '\n';
- if (out.dbcnt >= out.dbsz)
- dd_out(0);
- }
- if (in.dbcnt)
- (void)memmove(in.db, in.dbp - in.dbcnt, in.dbcnt);
- in.dbp = in.db + in.dbcnt;
-}
-
-void
-unblock_close(void)
-{
- uint64_t cnt;
- u_char *t;
-
- if (in.dbcnt) {
- warnx("%s: short input record", in.name);
- for (t = in.db + in.dbcnt - 1; t >= in.db && *t == ' '; --t);
- if (t >= in.db) {
- cnt = t - in.db + 1;
- (void)memmove(out.dbp, in.db, cnt);
- out.dbp += cnt;
- out.dbcnt += cnt;
- }
- ++out.dbcnt;
- *out.dbp++ = '\n';
- }
-}
-
-#endif /* NO_CONV */
diff --git a/toolbox/upstream-netbsd/bin/dd/dd.c b/toolbox/upstream-netbsd/bin/dd/dd.c
deleted file mode 100644
index 03d080c..0000000
--- a/toolbox/upstream-netbsd/bin/dd/dd.c
+++ /dev/null
@@ -1,598 +0,0 @@
-/* $NetBSD: dd.c,v 1.49 2012/02/21 01:49:01 matt Exp $ */
-
-/*-
- * Copyright (c) 1991, 1993, 1994
- * The Regents of the University of California. All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Keith Muller of the University of California, San Diego and Lance
- * Visser of Convex Computer Corporation.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the University nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#include <sys/cdefs.h>
-#ifndef lint
-__COPYRIGHT("@(#) Copyright (c) 1991, 1993, 1994\
- The Regents of the University of California. All rights reserved.");
-#endif /* not lint */
-
-#ifndef lint
-#if 0
-static char sccsid[] = "@(#)dd.c 8.5 (Berkeley) 4/2/94";
-#else
-__RCSID("$NetBSD: dd.c,v 1.49 2012/02/21 01:49:01 matt Exp $");
-#endif
-#endif /* not lint */
-
-#include <sys/param.h>
-#include <sys/stat.h>
-#include <sys/ioctl.h>
-#include <sys/mtio.h>
-#include <sys/time.h>
-
-#include <ctype.h>
-#include <err.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <locale.h>
-#include <signal.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-
-#include "dd.h"
-#include "extern.h"
-
-static void dd_close(void);
-static void dd_in(void);
-static void getfdtype(IO *);
-static void redup_clean_fd(IO *);
-static void setup(void);
-
-int main(int, char *[]);
-
-IO in, out; /* input/output state */
-STAT st; /* statistics */
-void (*cfunc)(void); /* conversion function */
-uint64_t cpy_cnt; /* # of blocks to copy */
-static off_t pending = 0; /* pending seek if sparse */
-u_int ddflags; /* conversion options */
-uint64_t cbsz; /* conversion block size */
-u_int files_cnt = 1; /* # of files to copy */
-uint64_t progress = 0; /* display sign of life */
-const u_char *ctab; /* conversion table */
-sigset_t infoset; /* a set blocking SIGINFO */
-const char *msgfmt = "posix"; /* default summary() message format */
-
-/*
- * Ops for stdin/stdout and crunch'd dd. These are always host ops.
- */
-static const struct ddfops ddfops_stdfd = {
- .op_open = open,
- .op_close = close,
- .op_fcntl = fcntl,
- .op_ioctl = ioctl,
- .op_fstat = fstat,
- .op_fsync = fsync,
- .op_ftruncate = ftruncate,
- .op_lseek = lseek,
- .op_read = read,
- .op_write = write,
-};
-extern const struct ddfops ddfops_prog;
-
-int
-main(int argc, char *argv[])
-{
- int ch;
-
- setprogname(argv[0]);
- (void)setlocale(LC_ALL, "");
-
- while ((ch = getopt(argc, argv, "")) != -1) {
- switch (ch) {
- default:
- errx(EXIT_FAILURE, "usage: dd [operand ...]");
- /* NOTREACHED */
- }
- }
- argc -= (optind - 1);
- argv += (optind - 1);
-
- jcl(argv);
-#ifndef CRUNCHOPS
- if (ddfops_prog.op_init && ddfops_prog.op_init() == -1)
- err(1, "prog init");
-#endif
- setup();
-
- (void)signal(SIGINFO, summaryx);
- (void)signal(SIGINT, terminate);
- (void)sigemptyset(&infoset);
- (void)sigaddset(&infoset, SIGINFO);
-
- (void)atexit(summary);
-
- while (files_cnt--)
- dd_in();
-
- dd_close();
- exit(0);
- /* NOTREACHED */
-}
-
-static void
-setup(void)
-{
-#ifdef CRUNCHOPS
- const struct ddfops *prog_ops = &ddfops_stdfd;
-#else
- const struct ddfops *prog_ops = &ddfops_prog;
-#endif
-
- if (in.name == NULL) {
- in.name = "stdin";
- in.fd = STDIN_FILENO;
- in.ops = &ddfops_stdfd;
- } else {
- in.ops = prog_ops;
- in.fd = ddop_open(in, in.name, O_RDONLY, 0);
- if (in.fd < 0)
- err(EXIT_FAILURE, "%s", in.name);
- /* NOTREACHED */
-
- /* Ensure in.fd is outside the stdio descriptor range */
- redup_clean_fd(&in);
- }
-
- getfdtype(&in);
-
- if (files_cnt > 1 && !(in.flags & ISTAPE)) {
- errx(EXIT_FAILURE, "files is not supported for non-tape devices");
- /* NOTREACHED */
- }
-
- if (out.name == NULL) {
- /* No way to check for read access here. */
- out.fd = STDOUT_FILENO;
- out.name = "stdout";
- out.ops = &ddfops_stdfd;
- } else {
- out.ops = prog_ops;
-#define OFLAGS \
- (O_CREAT | (ddflags & (C_SEEK | C_NOTRUNC) ? 0 : O_TRUNC))
- out.fd = ddop_open(out, out.name, O_RDWR | OFLAGS, DEFFILEMODE);
- /*
- * May not have read access, so try again with write only.
- * Without read we may have a problem if output also does
- * not support seeks.
- */
- if (out.fd < 0) {
- out.fd = ddop_open(out, out.name, O_WRONLY | OFLAGS,
- DEFFILEMODE);
- out.flags |= NOREAD;
- }
- if (out.fd < 0) {
- err(EXIT_FAILURE, "%s", out.name);
- /* NOTREACHED */
- }
-
- /* Ensure out.fd is outside the stdio descriptor range */
- redup_clean_fd(&out);
- }
-
- getfdtype(&out);
-
- /*
- * Allocate space for the input and output buffers. If not doing
- * record oriented I/O, only need a single buffer.
- */
- if (!(ddflags & (C_BLOCK|C_UNBLOCK))) {
- size_t dbsz = out.dbsz;
- if (!(ddflags & C_BS))
- dbsz += in.dbsz - 1;
- if ((in.db = malloc(dbsz)) == NULL) {
- err(EXIT_FAILURE, NULL);
- /* NOTREACHED */
- }
- out.db = in.db;
- } else if ((in.db =
- malloc((u_int)(MAX(in.dbsz, cbsz) + cbsz))) == NULL ||
- (out.db = malloc((u_int)(out.dbsz + cbsz))) == NULL) {
- err(EXIT_FAILURE, NULL);
- /* NOTREACHED */
- }
- in.dbp = in.db;
- out.dbp = out.db;
-
- /* Position the input/output streams. */
- if (in.offset)
- pos_in();
- if (out.offset)
- pos_out();
-
- /*
- * Truncate the output file; ignore errors because it fails on some
- * kinds of output files, tapes, for example.
- */
- if ((ddflags & (C_OF | C_SEEK | C_NOTRUNC)) == (C_OF | C_SEEK))
- (void)ddop_ftruncate(out, out.fd, (off_t)out.offset * out.dbsz);
-
- /*
- * If converting case at the same time as another conversion, build a
- * table that does both at once. If just converting case, use the
- * built-in tables.
- */
- if (ddflags & (C_LCASE|C_UCASE)) {
-#ifdef NO_CONV
- /* Should not get here, but just in case... */
- errx(EXIT_FAILURE, "case conv and -DNO_CONV");
- /* NOTREACHED */
-#else /* NO_CONV */
- u_int cnt;
-
- if (ddflags & C_ASCII || ddflags & C_EBCDIC) {
- if (ddflags & C_LCASE) {
- for (cnt = 0; cnt < 256; ++cnt)
- casetab[cnt] = tolower(ctab[cnt]);
- } else {
- for (cnt = 0; cnt < 256; ++cnt)
- casetab[cnt] = toupper(ctab[cnt]);
- }
- } else {
- if (ddflags & C_LCASE) {
- for (cnt = 0; cnt < 256; ++cnt)
- casetab[cnt] = tolower(cnt);
- } else {
- for (cnt = 0; cnt < 256; ++cnt)
- casetab[cnt] = toupper(cnt);
- }
- }
-
- ctab = casetab;
-#endif /* NO_CONV */
- }
-
- (void)gettimeofday(&st.start, NULL); /* Statistics timestamp. */
-}
-
-static void
-getfdtype(IO *io)
-{
- struct mtget mt;
- struct stat sb;
-
- if (io->ops->op_fstat(io->fd, &sb)) {
- err(EXIT_FAILURE, "%s", io->name);
- /* NOTREACHED */
- }
- if (S_ISCHR(sb.st_mode))
- io->flags |= io->ops->op_ioctl(io->fd, MTIOCGET, &mt)
- ? ISCHR : ISTAPE;
- else if (io->ops->op_lseek(io->fd, (off_t)0, SEEK_CUR) == -1
- && errno == ESPIPE)
- io->flags |= ISPIPE; /* XXX fixed in 4.4BSD */
-}
-
-/*
- * Move the parameter file descriptor to a descriptor that is outside the
- * stdio descriptor range, if necessary. This is required to avoid
- * accidentally outputting completion or error messages into the
- * output file that were intended for the tty.
- */
-static void
-redup_clean_fd(IO *io)
-{
- int fd = io->fd;
- int newfd;
-
- if (fd != STDIN_FILENO && fd != STDOUT_FILENO &&
- fd != STDERR_FILENO)
- /* File descriptor is ok, return immediately. */
- return;
-
- /*
- * 3 is the first descriptor greater than STD*_FILENO. Any
- * free descriptor valued 3 or above is acceptable...
- */
- newfd = io->ops->op_fcntl(fd, F_DUPFD, 3);
- if (newfd < 0) {
- err(EXIT_FAILURE, "dupfd IO");
- /* NOTREACHED */
- }
-
- io->ops->op_close(fd);
- io->fd = newfd;
-}
-
-static void
-dd_in(void)
-{
- int flags;
- int64_t n;
-
- for (flags = ddflags;;) {
- if (cpy_cnt && (st.in_full + st.in_part) >= cpy_cnt)
- return;
-
- /*
- * Clear the buffer first if doing "sync" on input.
- * If doing block operations use spaces. This will
- * affect not only the C_NOERROR case, but also the
- * last partial input block which should be padded
- * with zero and not garbage.
- */
- if (flags & C_SYNC) {
- if (flags & (C_BLOCK|C_UNBLOCK))
- (void)memset(in.dbp, ' ', in.dbsz);
- else
- (void)memset(in.dbp, 0, in.dbsz);
- }
-
- n = ddop_read(in, in.fd, in.dbp, in.dbsz);
- if (n == 0) {
- in.dbrcnt = 0;
- return;
- }
-
- /* Read error. */
- if (n < 0) {
-
- /*
- * If noerror not specified, die. POSIX requires that
- * the warning message be followed by an I/O display.
- */
- if (!(flags & C_NOERROR)) {
- err(EXIT_FAILURE, "%s", in.name);
- /* NOTREACHED */
- }
- warn("%s", in.name);
- summary();
-
- /*
- * If it's not a tape drive or a pipe, seek past the
- * error. If your OS doesn't do the right thing for
- * raw disks this section should be modified to re-read
- * in sector size chunks.
- */
- if (!(in.flags & (ISPIPE|ISTAPE)) &&
- ddop_lseek(in, in.fd, (off_t)in.dbsz, SEEK_CUR))
- warn("%s", in.name);
-
- /* If sync not specified, omit block and continue. */
- if (!(ddflags & C_SYNC))
- continue;
-
- /* Read errors count as full blocks. */
- in.dbcnt += in.dbrcnt = in.dbsz;
- ++st.in_full;
-
- /* Handle full input blocks. */
- } else if ((uint64_t)n == in.dbsz) {
- in.dbcnt += in.dbrcnt = n;
- ++st.in_full;
-
- /* Handle partial input blocks. */
- } else {
- /* If sync, use the entire block. */
- if (ddflags & C_SYNC)
- in.dbcnt += in.dbrcnt = in.dbsz;
- else
- in.dbcnt += in.dbrcnt = n;
- ++st.in_part;
- }
-
- /*
- * POSIX states that if bs is set and no other conversions
- * than noerror, notrunc or sync are specified, the block
- * is output without buffering as it is read.
- */
- if (ddflags & C_BS) {
- out.dbcnt = in.dbcnt;
- dd_out(1);
- in.dbcnt = 0;
- continue;
- }
-
- if (ddflags & C_SWAB) {
- if ((n = in.dbrcnt) & 1) {
- ++st.swab;
- --n;
- }
- swab(in.dbp, in.dbp, n);
- }
-
- in.dbp += in.dbrcnt;
- (*cfunc)();
- }
-}
-
-/*
- * Cleanup any remaining I/O and flush output. If necessary, output file
- * is truncated.
- */
-static void
-dd_close(void)
-{
-
- if (cfunc == def)
- def_close();
- else if (cfunc == block)
- block_close();
- else if (cfunc == unblock)
- unblock_close();
- if (ddflags & C_OSYNC && out.dbcnt < out.dbsz) {
- (void)memset(out.dbp, 0, out.dbsz - out.dbcnt);
- out.dbcnt = out.dbsz;
- }
- /* If there are pending sparse blocks, make sure
- * to write out the final block un-sparse
- */
- if ((out.dbcnt == 0) && pending) {
- memset(out.db, 0, out.dbsz);
- out.dbcnt = out.dbsz;
- out.dbp = out.db + out.dbcnt;
- pending -= out.dbsz;
- }
- if (out.dbcnt)
- dd_out(1);
-
- /*
- * Reporting nfs write error may be deferred until next
- * write(2) or close(2) system call. So, we need to do an
- * extra check. If an output is stdout, the file structure
- * may be shared with other processes and close(2) just
- * decreases the reference count.
- */
- if (out.fd == STDOUT_FILENO && ddop_fsync(out, out.fd) == -1
- && errno != EINVAL) {
- err(EXIT_FAILURE, "fsync stdout");
- /* NOTREACHED */
- }
- if (ddop_close(out, out.fd) == -1) {
- err(EXIT_FAILURE, "close");
- /* NOTREACHED */
- }
-}
-
-void
-dd_out(int force)
-{
- static int warned;
- int64_t cnt, n, nw;
- u_char *outp;
-
- /*
- * Write one or more blocks out. The common case is writing a full
- * output block in a single write; increment the full block stats.
- * Otherwise, we're into partial block writes. If a partial write,
- * and it's a character device, just warn. If a tape device, quit.
- *
- * The partial writes represent two cases. 1: Where the input block
- * was less than expected so the output block was less than expected.
- * 2: Where the input block was the right size but we were forced to
- * write the block in multiple chunks. The original versions of dd(1)
- * never wrote a block in more than a single write, so the latter case
- * never happened.
- *
- * One special case is if we're forced to do the write -- in that case
- * we play games with the buffer size, and it's usually a partial write.
- */
- outp = out.db;
- for (n = force ? out.dbcnt : out.dbsz;; n = out.dbsz) {
- for (cnt = n;; cnt -= nw) {
-
- if (!force && ddflags & C_SPARSE) {
- int sparse, i;
- sparse = 1; /* Is buffer sparse? */
- for (i = 0; i < cnt; i++)
- if (outp[i] != 0) {
- sparse = 0;
- break;
- }
- if (sparse) {
- pending += cnt;
- outp += cnt;
- nw = 0;
- break;
- }
- }
- if (pending != 0) {
- if (ddop_lseek(out,
- out.fd, pending, SEEK_CUR) == -1)
- err(EXIT_FAILURE, "%s: seek error creating sparse file",
- out.name);
- }
- nw = bwrite(&out, outp, cnt);
- if (nw <= 0) {
- if (nw == 0)
- errx(EXIT_FAILURE,
- "%s: end of device", out.name);
- /* NOTREACHED */
- if (errno != EINTR)
- err(EXIT_FAILURE, "%s", out.name);
- /* NOTREACHED */
- nw = 0;
- }
- if (pending) {
- st.bytes += pending;
- st.sparse += pending/out.dbsz;
- st.out_full += pending/out.dbsz;
- pending = 0;
- }
- outp += nw;
- st.bytes += nw;
- if (nw == n) {
- if ((uint64_t)n != out.dbsz)
- ++st.out_part;
- else
- ++st.out_full;
- break;
- }
- ++st.out_part;
- if (nw == cnt)
- break;
- if (out.flags & ISCHR && !warned) {
- warned = 1;
- warnx("%s: short write on character device", out.name);
- }
- if (out.flags & ISTAPE)
- errx(EXIT_FAILURE,
- "%s: short write on tape device", out.name);
- /* NOTREACHED */
-
- }
- if ((out.dbcnt -= n) < out.dbsz)
- break;
- }
-
- /* Reassemble the output block. */
- if (out.dbcnt)
- (void)memmove(out.db, out.dbp - out.dbcnt, out.dbcnt);
- out.dbp = out.db + out.dbcnt;
-
- if (progress && (st.out_full + st.out_part) % progress == 0)
- (void)write(STDERR_FILENO, ".", 1);
-}
-
-/*
- * A protected against SIGINFO write
- */
-ssize_t
-bwrite(IO *io, const void *buf, size_t len)
-{
- sigset_t oset;
- ssize_t rv;
- int oerrno;
-
- (void)sigprocmask(SIG_BLOCK, &infoset, &oset);
- rv = io->ops->op_write(io->fd, buf, len);
- oerrno = errno;
- (void)sigprocmask(SIG_SETMASK, &oset, NULL);
- errno = oerrno;
- return (rv);
-}
diff --git a/toolbox/upstream-netbsd/bin/dd/dd.h b/toolbox/upstream-netbsd/bin/dd/dd.h
deleted file mode 100644
index b01c7b3..0000000
--- a/toolbox/upstream-netbsd/bin/dd/dd.h
+++ /dev/null
@@ -1,127 +0,0 @@
-/* $NetBSD: dd.h,v 1.15 2011/02/04 19:42:12 pooka Exp $ */
-
-/*-
- * Copyright (c) 1991, 1993, 1994
- * The Regents of the University of California. All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Keith Muller of the University of California, San Diego and Lance
- * Visser of Convex Computer Corporation.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the University nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * @(#)dd.h 8.3 (Berkeley) 4/2/94
- */
-
-#include <sys/stat.h>
-
-struct ddfops {
- int (*op_init)(void);
-
- int (*op_open)(const char *, int, ...);
- int (*op_close)(int);
-
- int (*op_fcntl)(int, int, ...);
-#ifdef __ANDROID__
- int (*op_ioctl)(int, int, ...);
-#else
- int (*op_ioctl)(int, unsigned long, ...);
-#endif
-
- int (*op_fstat)(int, struct stat *);
- int (*op_fsync)(int);
- int (*op_ftruncate)(int, off_t);
-
- off_t (*op_lseek)(int, off_t, int);
-
- ssize_t (*op_read)(int, void *, size_t);
- ssize_t (*op_write)(int, const void *, size_t);
-};
-
-#define ddop_open(dir, a1, a2, ...) dir.ops->op_open(a1, a2, __VA_ARGS__)
-#define ddop_close(dir, a1) dir.ops->op_close(a1)
-#define ddop_fcntl(dir, a1, a2, ...) dir.ops->op_fcntl(a1, a2, __VA_ARGS__)
-#define ddop_ioctl(dir, a1, a2, ...) dir.ops->op_ioctl(a1, a2, __VA_ARGS__)
-#define ddop_fsync(dir, a1) dir.ops->op_fsync(a1)
-#define ddop_ftruncate(dir, a1, a2) dir.ops->op_ftruncate(a1, a2)
-#define ddop_lseek(dir, a1, a2, a3) dir.ops->op_lseek(a1, a2, a3)
-#define ddop_read(dir, a1, a2, a3) dir.ops->op_read(a1, a2, a3)
-#define ddop_write(dir, a1, a2, a3) dir.ops->op_write(a1, a2, a3)
-
-/* Input/output stream state. */
-typedef struct {
- u_char *db; /* buffer address */
- u_char *dbp; /* current buffer I/O address */
- uint64_t dbcnt; /* current buffer byte count */
- int64_t dbrcnt; /* last read byte count */
- uint64_t dbsz; /* buffer size */
-
-#define ISCHR 0x01 /* character device (warn on short) */
-#define ISPIPE 0x02 /* pipe (not truncatable) */
-#define ISTAPE 0x04 /* tape (not seekable) */
-#define NOREAD 0x08 /* not readable */
- u_int flags;
-
- const char *name; /* name */
- int fd; /* file descriptor */
- uint64_t offset; /* # of blocks to skip */
- struct ddfops const *ops; /* ops to use with fd */
-} IO;
-
-typedef struct {
- uint64_t in_full; /* # of full input blocks */
- uint64_t in_part; /* # of partial input blocks */
- uint64_t out_full; /* # of full output blocks */
- uint64_t out_part; /* # of partial output blocks */
- uint64_t trunc; /* # of truncated records */
- uint64_t swab; /* # of odd-length swab blocks */
- uint64_t sparse; /* # of sparse output blocks */
- uint64_t bytes; /* # of bytes written */
- struct timeval start; /* start time of dd */
-} STAT;
-
-/* Flags (in ddflags). */
-#define C_ASCII 0x00001
-#define C_BLOCK 0x00002
-#define C_BS 0x00004
-#define C_CBS 0x00008
-#define C_COUNT 0x00010
-#define C_EBCDIC 0x00020
-#define C_FILES 0x00040
-#define C_IBS 0x00080
-#define C_IF 0x00100
-#define C_LCASE 0x00200
-#define C_NOERROR 0x00400
-#define C_NOTRUNC 0x00800
-#define C_OBS 0x01000
-#define C_OF 0x02000
-#define C_SEEK 0x04000
-#define C_SKIP 0x08000
-#define C_SWAB 0x10000
-#define C_SYNC 0x20000
-#define C_UCASE 0x40000
-#define C_UNBLOCK 0x80000
-#define C_OSYNC 0x100000
-#define C_SPARSE 0x200000
diff --git a/toolbox/upstream-netbsd/bin/dd/dd_hostops.c b/toolbox/upstream-netbsd/bin/dd/dd_hostops.c
deleted file mode 100644
index d6e7a89..0000000
--- a/toolbox/upstream-netbsd/bin/dd/dd_hostops.c
+++ /dev/null
@@ -1,53 +0,0 @@
-/* $NetBSD: dd_hostops.c,v 1.1 2011/02/04 19:42:12 pooka Exp $ */
-
-/*-
- * Copyright (c) 2010 The NetBSD Foundation, Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
- * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
- * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
- * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include <sys/cdefs.h>
-#ifndef lint
-__RCSID("$NetBSD: dd_hostops.c,v 1.1 2011/02/04 19:42:12 pooka Exp $");
-#endif /* !lint */
-
-#include <sys/types.h>
-#include <sys/ioctl.h>
-
-#include <fcntl.h>
-#include <unistd.h>
-
-#include "dd.h"
-
-const struct ddfops ddfops_prog = {
- .op_open = open,
- .op_close = close,
- .op_fcntl = fcntl,
- .op_ioctl = ioctl,
- .op_fstat = fstat,
- .op_fsync = fsync,
- .op_ftruncate = ftruncate,
- .op_lseek = lseek,
- .op_read = read,
- .op_write = write,
-};
diff --git a/toolbox/upstream-netbsd/bin/dd/extern.h b/toolbox/upstream-netbsd/bin/dd/extern.h
deleted file mode 100644
index 9c59021..0000000
--- a/toolbox/upstream-netbsd/bin/dd/extern.h
+++ /dev/null
@@ -1,82 +0,0 @@
-/* $NetBSD: extern.h,v 1.22 2011/11/07 22:24:23 jym Exp $ */
-
-/*-
- * Copyright (c) 1991, 1993, 1994
- * The Regents of the University of California. All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Keith Muller of the University of California, San Diego and Lance
- * Visser of Convex Computer Corporation.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the University nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * @(#)extern.h 8.3 (Berkeley) 4/2/94
- */
-
-#include <sys/cdefs.h>
-
-#ifdef NO_CONV
-__dead void block(void);
-__dead void block_close(void);
-__dead void unblock(void);
-__dead void unblock_close(void);
-#else
-void block(void);
-void block_close(void);
-void unblock(void);
-void unblock_close(void);
-#endif
-
-#ifndef NO_MSGFMT
-int dd_write_msg(const char *, int);
-#endif
-
-void dd_out(int);
-void def(void);
-void def_close(void);
-void jcl(char **);
-void pos_in(void);
-void pos_out(void);
-void summary(void);
-void summaryx(int);
-__dead void terminate(int);
-void unblock(void);
-void unblock_close(void);
-ssize_t bwrite(IO *, const void *, size_t);
-
-extern IO in, out;
-extern STAT st;
-extern void (*cfunc)(void);
-extern uint64_t cpy_cnt;
-extern uint64_t cbsz;
-extern u_int ddflags;
-extern u_int files_cnt;
-extern uint64_t progress;
-extern const u_char *ctab;
-extern const u_char a2e_32V[], a2e_POSIX[];
-extern const u_char e2a_32V[], e2a_POSIX[];
-extern const u_char a2ibm_32V[], a2ibm_POSIX[];
-extern u_char casetab[];
-extern const char *msgfmt;
diff --git a/toolbox/upstream-netbsd/bin/dd/misc.c b/toolbox/upstream-netbsd/bin/dd/misc.c
deleted file mode 100644
index 0fac98b..0000000
--- a/toolbox/upstream-netbsd/bin/dd/misc.c
+++ /dev/null
@@ -1,342 +0,0 @@
-/* $NetBSD: misc.c,v 1.23 2011/11/07 22:24:23 jym Exp $ */
-
-/*-
- * Copyright (c) 1991, 1993, 1994
- * The Regents of the University of California. All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Keith Muller of the University of California, San Diego and Lance
- * Visser of Convex Computer Corporation.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the University nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#include <sys/cdefs.h>
-#ifndef lint
-#if 0
-static char sccsid[] = "@(#)misc.c 8.3 (Berkeley) 4/2/94";
-#else
-__RCSID("$NetBSD: misc.c,v 1.23 2011/11/07 22:24:23 jym Exp $");
-#endif
-#endif /* not lint */
-
-#include <sys/param.h>
-#include <sys/types.h>
-#include <sys/time.h>
-
-#include <err.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <util.h>
-#include <inttypes.h>
-
-#include "dd.h"
-#include "extern.h"
-
-#define tv2mS(tv) ((tv).tv_sec * 1000LL + ((tv).tv_usec + 500) / 1000)
-
-static void posix_summary(void);
-#ifndef NO_MSGFMT
-static void custom_summary(void);
-static void human_summary(void);
-static void quiet_summary(void);
-
-static void buffer_write(const char *, size_t, int);
-#endif /* NO_MSGFMT */
-
-void
-summary(void)
-{
-
- if (progress)
- (void)write(STDERR_FILENO, "\n", 1);
-
-#ifdef NO_MSGFMT
- return posix_summary();
-#else /* NO_MSGFMT */
- if (strncmp(msgfmt, "human", sizeof("human")) == 0)
- return human_summary();
-
- if (strncmp(msgfmt, "posix", sizeof("posix")) == 0)
- return posix_summary();
-
- if (strncmp(msgfmt, "quiet", sizeof("quiet")) == 0)
- return quiet_summary();
-
- return custom_summary();
-#endif /* NO_MSGFMT */
-}
-
-static void
-posix_summary(void)
-{
- char buf[100];
- int64_t mS;
- struct timeval tv;
-
- if (progress)
- (void)write(STDERR_FILENO, "\n", 1);
-
- (void)gettimeofday(&tv, NULL);
- mS = tv2mS(tv) - tv2mS(st.start);
- if (mS == 0)
- mS = 1;
-
- /* Use snprintf(3) so that we don't reenter stdio(3). */
- (void)snprintf(buf, sizeof(buf),
- "%llu+%llu records in\n%llu+%llu records out\n",
- (unsigned long long)st.in_full, (unsigned long long)st.in_part,
- (unsigned long long)st.out_full, (unsigned long long)st.out_part);
- (void)write(STDERR_FILENO, buf, strlen(buf));
- if (st.swab) {
- (void)snprintf(buf, sizeof(buf), "%llu odd length swab %s\n",
- (unsigned long long)st.swab,
- (st.swab == 1) ? "block" : "blocks");
- (void)write(STDERR_FILENO, buf, strlen(buf));
- }
- if (st.trunc) {
- (void)snprintf(buf, sizeof(buf), "%llu truncated %s\n",
- (unsigned long long)st.trunc,
- (st.trunc == 1) ? "block" : "blocks");
- (void)write(STDERR_FILENO, buf, strlen(buf));
- }
- if (st.sparse) {
- (void)snprintf(buf, sizeof(buf), "%llu sparse output %s\n",
- (unsigned long long)st.sparse,
- (st.sparse == 1) ? "block" : "blocks");
- (void)write(STDERR_FILENO, buf, strlen(buf));
- }
- (void)snprintf(buf, sizeof(buf),
- "%llu bytes transferred in %lu.%03d secs (%llu bytes/sec)\n",
- (unsigned long long) st.bytes,
- (long) (mS / 1000),
- (int) (mS % 1000),
- (unsigned long long) (st.bytes * 1000LL / mS));
- (void)write(STDERR_FILENO, buf, strlen(buf));
-}
-
-/* ARGSUSED */
-void
-summaryx(int notused)
-{
-
- summary();
-}
-
-/* ARGSUSED */
-void
-terminate(int signo)
-{
-
- summary();
- (void)raise_default_signal(signo);
- _exit(127);
-}
-
-#ifndef NO_MSGFMT
-/*
- * Buffer write(2) calls
- */
-static void
-buffer_write(const char *str, size_t size, int flush)
-{
- static char wbuf[128];
- static size_t cnt = 0; /* Internal counter to allow wbuf to wrap */
-
- unsigned int i;
-
- for (i = 0; i < size; i++) {
- if (str != NULL) {
- wbuf[cnt++] = str[i];
- }
- if (cnt >= sizeof(wbuf)) {
- (void)write(STDERR_FILENO, wbuf, cnt);
- cnt = 0;
- }
- }
-
- if (flush != 0) {
- (void)write(STDERR_FILENO, wbuf, cnt);
- cnt = 0;
- }
-}
-
-/*
- * Write summary to stderr according to format 'fmt'. If 'enable' is 0, it
- * will not attempt to write anything. Can be used to validate the
- * correctness of the 'fmt' string.
- */
-int
-dd_write_msg(const char *fmt, int enable)
-{
- char hbuf[7], nbuf[32];
- const char *ptr;
- int64_t mS;
- struct timeval tv;
-
- (void)gettimeofday(&tv, NULL);
- mS = tv2mS(tv) - tv2mS(st.start);
- if (mS == 0)
- mS = 1;
-
-#define ADDC(c) do { if (enable != 0) buffer_write(&c, 1, 0); } \
- while (/*CONSTCOND*/0)
-#define ADDS(p) do { if (enable != 0) buffer_write(p, strlen(p), 0); } \
- while (/*CONSTCOND*/0)
-
- for (ptr = fmt; *ptr; ptr++) {
- if (*ptr != '%') {
- ADDC(*ptr);
- continue;
- }
-
- switch (*++ptr) {
- case 'b':
- (void)snprintf(nbuf, sizeof(nbuf), "%llu",
- (unsigned long long)st.bytes);
- ADDS(nbuf);
- break;
- case 'B':
- if (humanize_number(hbuf, sizeof(hbuf),
- st.bytes, "B",
- HN_AUTOSCALE, HN_DECIMAL) == -1)
- warnx("humanize_number (bytes transferred)");
- ADDS(hbuf);
- break;
- case 'e':
- (void)snprintf(nbuf, sizeof(nbuf), "%llu",
- (unsigned long long) (st.bytes * 1000LL / mS));
- ADDS(nbuf);
- break;
- case 'E':
- if (humanize_number(hbuf, sizeof(hbuf),
- st.bytes * 1000LL / mS, "B",
- HN_AUTOSCALE, HN_DECIMAL) == -1)
- warnx("humanize_number (bytes per second)");
- ADDS(hbuf); ADDS("/sec");
- break;
- case 'i':
- (void)snprintf(nbuf, sizeof(nbuf), "%llu",
- (unsigned long long)st.in_part);
- ADDS(nbuf);
- break;
- case 'I':
- (void)snprintf(nbuf, sizeof(nbuf), "%llu",
- (unsigned long long)st.in_full);
- ADDS(nbuf);
- break;
- case 'o':
- (void)snprintf(nbuf, sizeof(nbuf), "%llu",
- (unsigned long long)st.out_part);
- ADDS(nbuf);
- break;
- case 'O':
- (void)snprintf(nbuf, sizeof(nbuf), "%llu",
- (unsigned long long)st.out_full);
- ADDS(nbuf);
- break;
- case 's':
- (void)snprintf(nbuf, sizeof(nbuf), "%li.%03d",
- (long) (mS / 1000), (int) (mS % 1000));
- ADDS(nbuf);
- break;
- case 'p':
- (void)snprintf(nbuf, sizeof(nbuf), "%llu",
- (unsigned long long)st.sparse);
- ADDS(nbuf);
- break;
- case 't':
- (void)snprintf(nbuf, sizeof(nbuf), "%llu",
- (unsigned long long)st.trunc);
- ADDS(nbuf);
- break;
- case 'w':
- (void)snprintf(nbuf, sizeof(nbuf), "%llu",
- (unsigned long long)st.swab);
- ADDS(nbuf);
- break;
- case 'P':
- ADDS("block");
- if (st.sparse != 1) ADDS("s");
- break;
- case 'T':
- ADDS("block");
- if (st.trunc != 1) ADDS("s");
- break;
- case 'W':
- ADDS("block");
- if (st.swab != 1) ADDS("s");
- break;
- case '%':
- ADDC(*ptr);
- break;
- default:
- if (*ptr == '\0')
- goto done;
- errx(EXIT_FAILURE, "unknown specifier '%c' in "
- "msgfmt string", *ptr);
- /* NOTREACHED */
- }
- }
-
-done:
- /* flush buffer */
- buffer_write(NULL, 0, 1);
- return 0;
-}
-
-static void
-custom_summary(void)
-{
-
- dd_write_msg(msgfmt, 1);
-}
-
-static void
-human_summary(void)
-{
- (void)dd_write_msg("%I+%i records in\n%O+%o records out\n", 1);
- if (st.swab) {
- (void)dd_write_msg("%w odd length swab %W\n", 1);
- }
- if (st.trunc) {
- (void)dd_write_msg("%t truncated %T\n", 1);
- }
- if (st.sparse) {
- (void)dd_write_msg("%p sparse output %P\n", 1);
- }
- (void)dd_write_msg("%b bytes (%B) transferred in %s secs "
- "(%e bytes/sec - %E)\n", 1);
-}
-
-static void
-quiet_summary(void)
-{
-
- /* stay quiet */
-}
-#endif /* NO_MSGFMT */
diff --git a/toolbox/upstream-netbsd/bin/dd/position.c b/toolbox/upstream-netbsd/bin/dd/position.c
deleted file mode 100644
index 36dd580..0000000
--- a/toolbox/upstream-netbsd/bin/dd/position.c
+++ /dev/null
@@ -1,185 +0,0 @@
-/* $NetBSD: position.c,v 1.18 2010/11/22 21:04:28 pooka Exp $ */
-
-/*-
- * Copyright (c) 1991, 1993, 1994
- * The Regents of the University of California. All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Keith Muller of the University of California, San Diego and Lance
- * Visser of Convex Computer Corporation.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the University nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#include <sys/cdefs.h>
-#ifndef lint
-#if 0
-static char sccsid[] = "@(#)position.c 8.3 (Berkeley) 4/2/94";
-#else
-__RCSID("$NetBSD: position.c,v 1.18 2010/11/22 21:04:28 pooka Exp $");
-#endif
-#endif /* not lint */
-
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <sys/ioctl.h>
-#include <sys/mtio.h>
-#include <sys/time.h>
-
-#include <err.h>
-#include <errno.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-
-#include "dd.h"
-#include "extern.h"
-
-/*
- * Position input/output data streams before starting the copy. Device type
- * dependent. Seekable devices use lseek, and the rest position by reading.
- * Seeking past the end of file can cause null blocks to be written to the
- * output.
- */
-void
-pos_in(void)
-{
- int bcnt, cnt, nr, warned;
-
- /* If not a pipe or tape device, try to seek on it. */
- if (!(in.flags & (ISPIPE|ISTAPE))) {
- if (ddop_lseek(in, in.fd,
- (off_t)in.offset * (off_t)in.dbsz, SEEK_CUR) == -1) {
- err(EXIT_FAILURE, "%s", in.name);
- /* NOTREACHED */
- }
- return;
- /* NOTREACHED */
- }
-
- /*
- * Read the data. If a pipe, read until satisfy the number of bytes
- * being skipped. No differentiation for reading complete and partial
- * blocks for other devices.
- */
- for (bcnt = in.dbsz, cnt = in.offset, warned = 0; cnt;) {
- if ((nr = ddop_read(in, in.fd, in.db, bcnt)) > 0) {
- if (in.flags & ISPIPE) {
- if (!(bcnt -= nr)) {
- bcnt = in.dbsz;
- --cnt;
- }
- } else
- --cnt;
- continue;
- }
-
- if (nr == 0) {
- if (files_cnt > 1) {
- --files_cnt;
- continue;
- }
- errx(EXIT_FAILURE, "skip reached end of input");
- /* NOTREACHED */
- }
-
- /*
- * Input error -- either EOF with no more files, or I/O error.
- * If noerror not set die. POSIX requires that the warning
- * message be followed by an I/O display.
- */
- if (ddflags & C_NOERROR) {
- if (!warned) {
-
- warn("%s", in.name);
- warned = 1;
- summary();
- }
- continue;
- }
- err(EXIT_FAILURE, "%s", in.name);
- /* NOTREACHED */
- }
-}
-
-void
-pos_out(void)
-{
- struct mtop t_op;
- int n;
- uint64_t cnt;
-
- /*
- * If not a tape, try seeking on the file. Seeking on a pipe is
- * going to fail, but don't protect the user -- they shouldn't
- * have specified the seek operand.
- */
- if (!(out.flags & ISTAPE)) {
- if (ddop_lseek(out, out.fd,
- (off_t)out.offset * (off_t)out.dbsz, SEEK_SET) == -1)
- err(EXIT_FAILURE, "%s", out.name);
- /* NOTREACHED */
- return;
- }
-
- /* If no read access, try using mtio. */
- if (out.flags & NOREAD) {
- t_op.mt_op = MTFSR;
- t_op.mt_count = out.offset;
-
- if (ddop_ioctl(out, out.fd, MTIOCTOP, &t_op) < 0)
- err(EXIT_FAILURE, "%s", out.name);
- /* NOTREACHED */
- return;
- }
-
- /* Read it. */
- for (cnt = 0; cnt < out.offset; ++cnt) {
- if ((n = ddop_read(out, out.fd, out.db, out.dbsz)) > 0)
- continue;
-
- if (n < 0)
- err(EXIT_FAILURE, "%s", out.name);
- /* NOTREACHED */
-
- /*
- * If reach EOF, fill with NUL characters; first, back up over
- * the EOF mark. Note, cnt has not yet been incremented, so
- * the EOF read does not count as a seek'd block.
- */
- t_op.mt_op = MTBSR;
- t_op.mt_count = 1;
- if (ddop_ioctl(out, out.fd, MTIOCTOP, &t_op) == -1)
- err(EXIT_FAILURE, "%s", out.name);
- /* NOTREACHED */
-
- while (cnt++ < out.offset)
- if ((uint64_t)(n = bwrite(&out,
- out.db, out.dbsz)) != out.dbsz)
- err(EXIT_FAILURE, "%s", out.name);
- /* NOTREACHED */
- break;
- }
-}
diff --git a/toolbox/upstream-netbsd/include/namespace.h b/toolbox/upstream-netbsd/include/namespace.h
deleted file mode 100644
index e69de29..0000000
--- a/toolbox/upstream-netbsd/include/namespace.h
+++ /dev/null
diff --git a/toolbox/upstream-netbsd/include/sys/extattr.h b/toolbox/upstream-netbsd/include/sys/extattr.h
deleted file mode 100644
index e69de29..0000000
--- a/toolbox/upstream-netbsd/include/sys/extattr.h
+++ /dev/null
diff --git a/toolbox/upstream-netbsd/include/util.h b/toolbox/upstream-netbsd/include/util.h
deleted file mode 100644
index e69de29..0000000
--- a/toolbox/upstream-netbsd/include/util.h
+++ /dev/null
diff --git a/toolbox/upstream-netbsd/lib/libc/gen/getbsize.c b/toolbox/upstream-netbsd/lib/libc/gen/getbsize.c
deleted file mode 100644
index a9ce2c1..0000000
--- a/toolbox/upstream-netbsd/lib/libc/gen/getbsize.c
+++ /dev/null
@@ -1,118 +0,0 @@
-/* $NetBSD: getbsize.c,v 1.17 2012/06/25 22:32:43 abs Exp $ */
-
-/*-
- * Copyright (c) 1991, 1993
- * The Regents of the University of California. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the University nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#include <sys/cdefs.h>
-#if defined(LIBC_SCCS) && !defined(lint)
-#if 0
-static char sccsid[] = "@(#)getbsize.c 8.1 (Berkeley) 6/4/93";
-#else
-__RCSID("$NetBSD: getbsize.c,v 1.17 2012/06/25 22:32:43 abs Exp $");
-#endif
-#endif /* not lint */
-
-#include "namespace.h"
-
-#include <assert.h>
-#include <err.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#ifdef __weak_alias
-__weak_alias(getbsize,_getbsize)
-#endif
-
-char *
-getbsize(int *headerlenp, long *blocksizep)
-{
- static char header[20];
- long n, max, mul, blocksize;
- char *ep, *p;
- const char *form;
-
-#define KB (1024L)
-#define MB (1024L * 1024L)
-#define GB (1024L * 1024L * 1024L)
-#define MAXB GB /* No tera, peta, nor exa. */
- form = "";
- if ((p = getenv("BLOCKSIZE")) != NULL && *p != '\0') {
- if ((n = strtol(p, &ep, 10)) < 0)
- goto underflow;
- if (n == 0)
- n = 1;
- if (*ep && ep[1])
- goto fmterr;
- switch (*ep) {
- case 'G': case 'g':
- form = "G";
- max = MAXB / GB;
- mul = GB;
- break;
- case 'K': case 'k':
- form = "K";
- max = MAXB / KB;
- mul = KB;
- break;
- case 'M': case 'm':
- form = "M";
- max = MAXB / MB;
- mul = MB;
- break;
- case '\0':
- max = MAXB;
- mul = 1;
- break;
- default:
-fmterr: warnx("%s: unknown blocksize", p);
- n = 512;
- mul = 1;
- max = 0;
- break;
- }
- if (n > max) {
- warnx("maximum blocksize is %ldG", MAXB / GB);
- n = max;
- }
- if ((blocksize = n * mul) < 512) {
-underflow: warnx("%s: minimum blocksize is 512", p);
- form = "";
- blocksize = n = 512;
- }
- } else
- blocksize = n = 512;
-
- if (headerlenp)
- *headerlenp =
- snprintf(header, sizeof(header), "%ld%s-blocks", n, form);
- if (blocksizep)
- *blocksizep = blocksize;
- return (header);
-}
diff --git a/toolbox/upstream-netbsd/lib/libc/gen/humanize_number.c b/toolbox/upstream-netbsd/lib/libc/gen/humanize_number.c
deleted file mode 100644
index 533560f..0000000
--- a/toolbox/upstream-netbsd/lib/libc/gen/humanize_number.c
+++ /dev/null
@@ -1,161 +0,0 @@
-/* $NetBSD: humanize_number.c,v 1.16 2012/03/17 20:01:14 christos Exp $ */
-
-/*
- * Copyright (c) 1997, 1998, 1999, 2002 The NetBSD Foundation, Inc.
- * All rights reserved.
- *
- * This code is derived from software contributed to The NetBSD Foundation
- * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
- * NASA Ames Research Center, by Luke Mewburn and by Tomas Svensson.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
- * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
- * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
- * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include <sys/cdefs.h>
-#if defined(LIBC_SCCS) && !defined(lint)
-__RCSID("$NetBSD: humanize_number.c,v 1.16 2012/03/17 20:01:14 christos Exp $");
-#endif /* LIBC_SCCS and not lint */
-
-#include "namespace.h"
-#include <assert.h>
-#include <inttypes.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <locale.h>
-
-int
-humanize_number(char *buf, size_t len, int64_t bytes,
- const char *suffix, int scale, int flags)
-{
- const char *prefixes, *sep;
- int b, r, s1, s2, sign;
- int64_t divisor, max, post = 1;
- size_t i, baselen, maxscale;
-
- _DIAGASSERT(buf != NULL);
- _DIAGASSERT(suffix != NULL);
- _DIAGASSERT(scale >= 0);
-
- if (flags & HN_DIVISOR_1000) {
- /* SI for decimal multiplies */
- divisor = 1000;
- if (flags & HN_B)
- prefixes = "B\0k\0M\0G\0T\0P\0E";
- else
- prefixes = "\0\0k\0M\0G\0T\0P\0E";
- } else {
- /*
- * binary multiplies
- * XXX IEC 60027-2 recommends Ki, Mi, Gi...
- */
- divisor = 1024;
- if (flags & HN_B)
- prefixes = "B\0K\0M\0G\0T\0P\0E";
- else
- prefixes = "\0\0K\0M\0G\0T\0P\0E";
- }
-
-#define SCALE2PREFIX(scale) (&prefixes[(scale) << 1])
- maxscale = 7;
-
- if ((size_t)scale >= maxscale &&
- (scale & (HN_AUTOSCALE | HN_GETSCALE)) == 0)
- return (-1);
-
- if (buf == NULL || suffix == NULL)
- return (-1);
-
- if (len > 0)
- buf[0] = '\0';
- if (bytes < 0) {
- sign = -1;
- baselen = 3; /* sign, digit, prefix */
- if (-bytes < INT64_MAX / 100)
- bytes *= -100;
- else {
- bytes = -bytes;
- post = 100;
- baselen += 2;
- }
- } else {
- sign = 1;
- baselen = 2; /* digit, prefix */
- if (bytes < INT64_MAX / 100)
- bytes *= 100;
- else {
- post = 100;
- baselen += 2;
- }
- }
- if (flags & HN_NOSPACE)
- sep = "";
- else {
- sep = " ";
- baselen++;
- }
- baselen += strlen(suffix);
-
- /* Check if enough room for `x y' + suffix + `\0' */
- if (len < baselen + 1)
- return (-1);
-
- if (scale & (HN_AUTOSCALE | HN_GETSCALE)) {
- /* See if there is additional columns can be used. */
- for (max = 100, i = len - baselen; i-- > 0;)
- max *= 10;
-
- /*
- * Divide the number until it fits the given column.
- * If there will be an overflow by the rounding below,
- * divide once more.
- */
- for (i = 0; bytes >= max - 50 && i < maxscale; i++)
- bytes /= divisor;
-
- if (scale & HN_GETSCALE) {
- _DIAGASSERT(__type_fit(int, i));
- return (int)i;
- }
- } else
- for (i = 0; i < (size_t)scale && i < maxscale; i++)
- bytes /= divisor;
- bytes *= post;
-
- /* If a value <= 9.9 after rounding and ... */
- if (bytes < 995 && i > 0 && flags & HN_DECIMAL) {
- /* baselen + \0 + .N */
- if (len < baselen + 1 + 2)
- return (-1);
- b = ((int)bytes + 5) / 10;
- s1 = b / 10;
- s2 = b % 10;
- r = snprintf(buf, len, "%d%s%d%s%s%s",
- sign * s1, localeconv()->decimal_point, s2,
- sep, SCALE2PREFIX(i), suffix);
- } else
- r = snprintf(buf, len, "%" PRId64 "%s%s%s",
- sign * ((bytes + 50) / 100),
- sep, SCALE2PREFIX(i), suffix);
-
- return (r);
-}
diff --git a/toolbox/upstream-netbsd/lib/libc/stdlib/strsuftoll.c b/toolbox/upstream-netbsd/lib/libc/stdlib/strsuftoll.c
deleted file mode 100644
index 80fc52f..0000000
--- a/toolbox/upstream-netbsd/lib/libc/stdlib/strsuftoll.c
+++ /dev/null
@@ -1,249 +0,0 @@
-/* $NetBSD: strsuftoll.c,v 1.9 2011/10/22 22:08:47 christos Exp $ */
-/*-
- * Copyright (c) 2001-2002,2004 The NetBSD Foundation, Inc.
- * All rights reserved.
- *
- * This code is derived from software contributed to The NetBSD Foundation
- * by Luke Mewburn.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
- * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
- * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
- * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
- */
-/*-
- * Copyright (c) 1991, 1993, 1994
- * The Regents of the University of California. All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Keith Muller of the University of California, San Diego and Lance
- * Visser of Convex Computer Corporation.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the University nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#if HAVE_NBTOOL_CONFIG_H
-#include "nbtool_config.h"
-#endif
-
-#include <sys/cdefs.h>
-
-#if defined(LIBC_SCCS) && !defined(lint)
-__RCSID("$NetBSD: strsuftoll.c,v 1.9 2011/10/22 22:08:47 christos Exp $");
-#endif /* LIBC_SCCS and not lint */
-
-#ifdef _LIBC
-#include "namespace.h"
-#endif
-
-#if !HAVE_STRSUFTOLL
-
-#include <sys/types.h>
-#include <sys/time.h>
-
-#include <assert.h>
-#include <ctype.h>
-#include <err.h>
-#include <errno.h>
-#include <limits.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#ifdef _LIBC
-# ifdef __weak_alias
-__weak_alias(strsuftoll, _strsuftoll)
-__weak_alias(strsuftollx, _strsuftollx)
-# endif
-#endif /* LIBC */
-
-/*
- * Convert an expression of the following forms to a (u)int64_t.
- * 1) A positive decimal number.
- * 2) A positive decimal number followed by a b (mult by 512).
- * 3) A positive decimal number followed by a k (mult by 1024).
- * 4) A positive decimal number followed by a m (mult by 1048576).
- * 5) A positive decimal number followed by a g (mult by 1073741824).
- * 6) A positive decimal number followed by a t (mult by 1099511627776).
- * 7) A positive decimal number followed by a w (mult by sizeof int)
- * 8) Two or more positive decimal numbers (with/without k,b or w).
- * separated by x (also * for backwards compatibility), specifying
- * the product of the indicated values.
- * Returns the result upon successful conversion, or exits with an
- * appropriate error.
- *
- */
-/* LONGLONG */
-long long
-strsuftoll(const char *desc, const char *val,
- long long min, long long max)
-{
- long long result;
- char errbuf[100];
-
- result = strsuftollx(desc, val, min, max, errbuf, sizeof(errbuf));
- if (*errbuf != '\0')
- errx(EXIT_FAILURE, "%s", errbuf);
- return result;
-}
-
-/*
- * As strsuftoll(), but returns the error message into the provided buffer
- * rather than exiting with it.
- */
-/* LONGLONG */
-static long long
-__strsuftollx(const char *desc, const char *val,
- long long min, long long max, char *ebuf, size_t ebuflen, size_t depth)
-{
- long long num, t;
- char *expr;
-
- _DIAGASSERT(desc != NULL);
- _DIAGASSERT(val != NULL);
- _DIAGASSERT(ebuf != NULL);
-
- if (depth > 16) {
- snprintf(ebuf, ebuflen, "%s: Recursion limit exceeded", desc);
- return 0;
- }
-
- while (isspace((unsigned char)*val)) /* Skip leading space */
- val++;
-
- errno = 0;
- num = strtoll(val, &expr, 10);
- if (errno == ERANGE)
- goto erange; /* Overflow */
-
- if (expr == val) /* No digits */
- goto badnum;
-
- switch (*expr) {
- case 'b':
- t = num;
- num *= 512; /* 1 block */
- if (t > num)
- goto erange;
- ++expr;
- break;
- case 'k':
- t = num;
- num *= 1024; /* 1 kibibyte */
- if (t > num)
- goto erange;
- ++expr;
- break;
- case 'm':
- t = num;
- num *= 1048576; /* 1 mebibyte */
- if (t > num)
- goto erange;
- ++expr;
- break;
- case 'g':
- t = num;
- num *= 1073741824; /* 1 gibibyte */
- if (t > num)
- goto erange;
- ++expr;
- break;
- case 't':
- t = num;
- num *= 1099511627776LL; /* 1 tebibyte */
- if (t > num)
- goto erange;
- ++expr;
- break;
- case 'w':
- t = num;
- num *= sizeof(int); /* 1 word */
- if (t > num)
- goto erange;
- ++expr;
- break;
- }
-
- switch (*expr) {
- case '\0':
- break;
- case '*': /* Backward compatible */
- case 'x':
- t = num;
- num *= __strsuftollx(desc, expr + 1, min, max, ebuf, ebuflen,
- depth + 1);
- if (*ebuf != '\0')
- return 0;
- if (t > num) {
- erange:
- errno = ERANGE;
- snprintf(ebuf, ebuflen, "%s: %s", desc, strerror(errno));
- return 0;
- }
- break;
- default:
- badnum:
- snprintf(ebuf, ebuflen, "%s `%s': illegal number", desc, val);
- return 0;
- }
- if (num < min) {
- /* LONGLONG */
- snprintf(ebuf, ebuflen, "%s %lld is less than %lld.",
- desc, (long long)num, (long long)min);
- return 0;
- }
- if (num > max) {
- /* LONGLONG */
- snprintf(ebuf, ebuflen, "%s %lld is greater than %lld.",
- desc, (long long)num, (long long)max);
- return 0;
- }
- *ebuf = '\0';
- return num;
-}
-
-long long
-strsuftollx(const char *desc, const char *val,
- long long min, long long max, char *ebuf, size_t ebuflen)
-{
- return __strsuftollx(desc, val, min, max, ebuf, ebuflen, 0);
-}
-#endif /* !HAVE_STRSUFTOLL */
diff --git a/toolbox/upstream-netbsd/lib/libc/string/swab.c b/toolbox/upstream-netbsd/lib/libc/string/swab.c
deleted file mode 100644
index 392b186..0000000
--- a/toolbox/upstream-netbsd/lib/libc/string/swab.c
+++ /dev/null
@@ -1,80 +0,0 @@
-/* $NetBSD: swab.c,v 1.18 2011/01/04 17:14:07 martin Exp $ */
-
-/*
- * Copyright (c) 1988, 1993
- * The Regents of the University of California. All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Jeffrey Mogul.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the University nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#include <sys/cdefs.h>
-#if defined(LIBC_SCCS) && !defined(lint)
-#if 0
-static char sccsid[] = "@(#)swab.c 8.1 (Berkeley) 6/4/93";
-#else
-__RCSID("$NetBSD: swab.c,v 1.18 2011/01/04 17:14:07 martin Exp $");
-#endif
-#endif /* LIBC_SCCS and not lint */
-
-#include <assert.h>
-#include <unistd.h>
-
-void
-swab(const void * __restrict from, void * __restrict to, ssize_t len)
-{
- char temp;
- const char *fp;
- char *tp;
-
- if (len <= 1)
- return;
-
- _DIAGASSERT(from != NULL);
- _DIAGASSERT(to != NULL);
-
- len /= 2;
- fp = (const char *)from;
- tp = (char *)to;
-#define STEP temp = *fp++,*tp++ = *fp++,*tp++ = temp
-
- if (__predict_false(len == 1)) {
- STEP;
- return;
- }
-
- /* round to multiple of 8 */
- while ((--len % 8) != 0)
- STEP;
- len /= 8;
- if (len == 0)
- return;
- while (len-- != 0) {
- STEP; STEP; STEP; STEP;
- STEP; STEP; STEP; STEP;
- }
-}
diff --git a/toolbox/upstream-netbsd/lib/libutil/raise_default_signal.c b/toolbox/upstream-netbsd/lib/libutil/raise_default_signal.c
deleted file mode 100644
index 50cffd4..0000000
--- a/toolbox/upstream-netbsd/lib/libutil/raise_default_signal.c
+++ /dev/null
@@ -1,117 +0,0 @@
-/* $NetBSD: raise_default_signal.c,v 1.3 2008/04/28 20:23:03 martin Exp $ */
-
-/*-
- * Copyright (c) 2007 The NetBSD Foundation, Inc.
- * All rights reserved.
- *
- * This code is derived from software contributed to The NetBSD Foundation
- * by Luke Mewburn.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
- * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
- * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
- * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
- */
-
-#if HAVE_NBTOOL_CONFIG_H
-#include "nbtool_config.h"
-#endif
-
-#include <sys/cdefs.h>
-#if defined(LIBC_SCCS) && !defined(lint)
-__RCSID("$NetBSD: raise_default_signal.c,v 1.3 2008/04/28 20:23:03 martin Exp $");
-#endif
-
-#include <errno.h>
-#include <signal.h>
-#include <stdio.h>
-#include <string.h>
-#include <util.h>
-
-#if ! HAVE_RAISE_DEFAULT_SIGNAL
-/*
- * raise_default_signal sig
- * Raise the default signal handler for sig, by
- * - block all signals
- * - set the signal handler to SIG_DFL
- * - raise the signal
- * - unblock the signal to deliver it
- *
- * The original signal mask and signal handler is restored on exit
- * (whether successful or not).
- *
- * Returns 0 on success, or -1 on failure with errno set to
- * on of the values for sigemptyset(), sigaddset(), sigprocmask(),
- * sigaction(), or raise().
- */
-int
-raise_default_signal(int sig)
-{
- struct sigaction origact, act;
- sigset_t origmask, fullmask, mask;
- int retval, oerrno;
-
- retval = -1;
-
- /* Setup data structures */
- /* XXX memset(3) isn't async-safe according to signal(7) */
- (void)memset(&act, 0, sizeof(act));
- act.sa_handler = SIG_DFL;
- act.sa_flags = 0;
- if ((sigemptyset(&act.sa_mask) == -1) ||
- (sigfillset(&fullmask) == -1) ||
- (sigemptyset(&mask) == -1) ||
- (sigaddset(&mask, sig) == -1))
- goto restore_none;
-
- /* Block all signals */
- if (sigprocmask(SIG_BLOCK, &fullmask, &origmask) == -1)
- goto restore_none;
- /* (use 'goto restore_mask' to restore state) */
-
- /* Enable the SIG_DFL handler */
- if (sigaction(sig, &act, &origact) == -1)
- goto restore_mask;
- /* (use 'goto restore_act' to restore state) */
-
- /* Raise the signal, and unblock the signal to deliver it */
- if ((raise(sig) == -1) ||
- (sigprocmask(SIG_UNBLOCK, &mask, NULL) == -1))
- goto restore_act;
-
- /* Flag successful raise() */
- retval = 0;
-
- /* Restore the original handler */
- restore_act:
- oerrno = errno;
- (void)sigaction(sig, &origact, NULL);
- errno = oerrno;
-
- /* Restore the original mask */
- restore_mask:
- oerrno = errno;
- (void)sigprocmask(SIG_SETMASK, &origmask, NULL);
- errno = oerrno;
-
- restore_none:
- return retval;
-}
-
-#endif /* ! HAVE_RAISE_DEFAULT_SIGNAL */
diff --git a/toolbox/upstream-netbsd/usr.bin/grep/fastgrep.c b/toolbox/upstream-netbsd/usr.bin/grep/fastgrep.c
deleted file mode 100644
index 2fcd864..0000000
--- a/toolbox/upstream-netbsd/usr.bin/grep/fastgrep.c
+++ /dev/null
@@ -1,336 +0,0 @@
-/* $OpenBSD: util.c,v 1.36 2007/10/02 17:59:18 otto Exp $ */
-/* $FreeBSD: head/usr.bin/grep/fastgrep.c 211496 2010-08-19 09:28:59Z des $ */
-
-/*-
- * Copyright (c) 1999 James Howard and Dag-Erling Coïdan Smørgrav
- * Copyright (C) 2008 Gabor Kovesdan <gabor@FreeBSD.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-/*
- * XXX: This file is a speed up for grep to cover the defects of the
- * regex library. These optimizations should practically be implemented
- * there keeping this code clean. This is a future TODO, but for the
- * meantime, we need to use this workaround.
- */
-
-#if HAVE_NBTOOL_CONFIG_H
-#include "nbtool_config.h"
-#endif
-
-#include <sys/cdefs.h>
-__RCSID("$NetBSD: fastgrep.c,v 1.5 2011/04/18 03:27:40 joerg Exp $");
-
-#include <limits.h>
-#include <stdbool.h>
-#include <stdlib.h>
-#include <string.h>
-#include <wchar.h>
-#include <wctype.h>
-
-#include "grep.h"
-
-static inline int grep_cmp(const unsigned char *, const unsigned char *, size_t);
-static inline void grep_revstr(unsigned char *, int);
-
-void
-fgrepcomp(fastgrep_t *fg, const char *pat)
-{
- unsigned int i;
-
- /* Initialize. */
- fg->len = strlen(pat);
- fg->bol = false;
- fg->eol = false;
- fg->reversed = false;
-
- fg->pattern = (unsigned char *)grep_strdup(pat);
-
- /* Preprocess pattern. */
- for (i = 0; i <= UCHAR_MAX; i++)
- fg->qsBc[i] = fg->len;
- for (i = 1; i < fg->len; i++)
- fg->qsBc[fg->pattern[i]] = fg->len - i;
-}
-
-/*
- * Returns: -1 on failure, 0 on success
- */
-int
-fastcomp(fastgrep_t *fg, const char *pat)
-{
- unsigned int i;
- int firstHalfDot = -1;
- int firstLastHalfDot = -1;
- int hasDot = 0;
- int lastHalfDot = 0;
- int shiftPatternLen;
-
- /* Initialize. */
- fg->len = strlen(pat);
- fg->bol = false;
- fg->eol = false;
- fg->reversed = false;
- fg->word = wflag;
-
- /* Remove end-of-line character ('$'). */
- if (fg->len > 0 && pat[fg->len - 1] == '$') {
- fg->eol = true;
- fg->len--;
- }
-
- /* Remove beginning-of-line character ('^'). */
- if (pat[0] == '^') {
- fg->bol = true;
- fg->len--;
- pat++;
- }
-
- if (fg->len >= 14 &&
- memcmp(pat, "[[:<:]]", 7) == 0 &&
- memcmp(pat + fg->len - 7, "[[:>:]]", 7) == 0) {
- fg->len -= 14;
- pat += 7;
- /* Word boundary is handled separately in util.c */
- fg->word = true;
- }
-
- /*
- * pat has been adjusted earlier to not include '^', '$' or
- * the word match character classes at the beginning and ending
- * of the string respectively.
- */
- fg->pattern = grep_malloc(fg->len + 1);
- memcpy(fg->pattern, pat, fg->len);
- fg->pattern[fg->len] = '\0';
-
- /* Look for ways to cheat...er...avoid the full regex engine. */
- for (i = 0; i < fg->len; i++) {
- /* Can still cheat? */
- if (fg->pattern[i] == '.') {
- hasDot = i;
- if (i < fg->len / 2) {
- if (firstHalfDot < 0)
- /* Closest dot to the beginning */
- firstHalfDot = i;
- } else {
- /* Closest dot to the end of the pattern. */
- lastHalfDot = i;
- if (firstLastHalfDot < 0)
- firstLastHalfDot = i;
- }
- } else {
- /* Free memory and let others know this is empty. */
- free(fg->pattern);
- fg->pattern = NULL;
- return (-1);
- }
- }
-
- /*
- * Determine if a reverse search would be faster based on the placement
- * of the dots.
- */
- if ((!(lflag || cflag)) && ((!(fg->bol || fg->eol)) &&
- ((lastHalfDot) && ((firstHalfDot < 0) ||
- ((fg->len - (lastHalfDot + 1)) < (size_t)firstHalfDot)))) &&
- !oflag && !color) {
- fg->reversed = true;
- hasDot = fg->len - (firstHalfDot < 0 ?
- firstLastHalfDot : firstHalfDot) - 1;
- grep_revstr(fg->pattern, fg->len);
- }
-
- /*
- * Normal Quick Search would require a shift based on the position the
- * next character after the comparison is within the pattern. With
- * wildcards, the position of the last dot effects the maximum shift
- * distance.
- * The closer to the end the wild card is the slower the search. A
- * reverse version of this algorithm would be useful for wildcards near
- * the end of the string.
- *
- * Examples:
- * Pattern Max shift
- * ------- ---------
- * this 5
- * .his 4
- * t.is 3
- * th.s 2
- * thi. 1
- */
-
- /* Adjust the shift based on location of the last dot ('.'). */
- shiftPatternLen = fg->len - hasDot;
-
- /* Preprocess pattern. */
- for (i = 0; i <= (signed)UCHAR_MAX; i++)
- fg->qsBc[i] = shiftPatternLen;
- for (i = hasDot + 1; i < fg->len; i++) {
- fg->qsBc[fg->pattern[i]] = fg->len - i;
- }
-
- /*
- * Put pattern back to normal after pre-processing to allow for easy
- * comparisons later.
- */
- if (fg->reversed)
- grep_revstr(fg->pattern, fg->len);
-
- return (0);
-}
-
-int
-grep_search(fastgrep_t *fg, const unsigned char *data, size_t len, regmatch_t *pmatch)
-{
- unsigned int j;
- int ret = REG_NOMATCH;
-
- if (pmatch->rm_so == (ssize_t)len)
- return (ret);
-
- if (fg->bol && pmatch->rm_so != 0) {
- pmatch->rm_so = len;
- pmatch->rm_eo = len;
- return (ret);
- }
-
- /* No point in going farther if we do not have enough data. */
- if (len < fg->len)
- return (ret);
-
- /* Only try once at the beginning or ending of the line. */
- if (fg->bol || fg->eol) {
- /* Simple text comparison. */
- /* Verify data is >= pattern length before searching on it. */
- if (len >= fg->len) {
- /* Determine where in data to start search at. */
- j = fg->eol ? len - fg->len : 0;
- if (!((fg->bol && fg->eol) && (len != fg->len)))
- if (grep_cmp(fg->pattern, data + j,
- fg->len) == -1) {
- pmatch->rm_so = j;
- pmatch->rm_eo = j + fg->len;
- ret = 0;
- }
- }
- } else if (fg->reversed) {
- /* Quick Search algorithm. */
- j = len;
- do {
- if (grep_cmp(fg->pattern, data + j - fg->len,
- fg->len) == -1) {
- pmatch->rm_so = j - fg->len;
- pmatch->rm_eo = j;
- ret = 0;
- break;
- }
- /* Shift if within bounds, otherwise, we are done. */
- if (j == fg->len)
- break;
- j -= fg->qsBc[data[j - fg->len - 1]];
- } while (j >= fg->len);
- } else {
- /* Quick Search algorithm. */
- j = pmatch->rm_so;
- do {
- if (grep_cmp(fg->pattern, data + j, fg->len) == -1) {
- pmatch->rm_so = j;
- pmatch->rm_eo = j + fg->len;
- ret = 0;
- break;
- }
-
- /* Shift if within bounds, otherwise, we are done. */
- if (j + fg->len == len)
- break;
- else
- j += fg->qsBc[data[j + fg->len]];
- } while (j <= (len - fg->len));
- }
-
- return (ret);
-}
-
-/*
- * Returns: i >= 0 on failure (position that it failed)
- * -1 on success
- */
-static inline int
-grep_cmp(const unsigned char *pat, const unsigned char *data, size_t len)
-{
- size_t size;
- wchar_t *wdata, *wpat;
- unsigned int i;
-
- if (iflag) {
- if ((size = mbstowcs(NULL, (const char *)data, 0)) ==
- ((size_t) - 1))
- return (-1);
-
- wdata = grep_malloc(size * sizeof(wint_t));
-
- if (mbstowcs(wdata, (const char *)data, size) ==
- ((size_t) - 1))
- return (-1);
-
- if ((size = mbstowcs(NULL, (const char *)pat, 0)) ==
- ((size_t) - 1))
- return (-1);
-
- wpat = grep_malloc(size * sizeof(wint_t));
-
- if (mbstowcs(wpat, (const char *)pat, size) == ((size_t) - 1))
- return (-1);
- for (i = 0; i < len; i++) {
- if ((towlower(wpat[i]) == towlower(wdata[i])) ||
- ((grepbehave != GREP_FIXED) && wpat[i] == L'.'))
- continue;
- free(wpat);
- free(wdata);
- return (i);
- }
- } else {
- for (i = 0; i < len; i++) {
- if ((pat[i] == data[i]) || ((grepbehave != GREP_FIXED) &&
- pat[i] == '.'))
- continue;
- return (i);
- }
- }
- return (-1);
-}
-
-static inline void
-grep_revstr(unsigned char *str, int len)
-{
- int i;
- char c;
-
- for (i = 0; i < len / 2; i++) {
- c = str[i];
- str[i] = str[len - i - 1];
- str[len - i - 1] = c;
- }
-}
diff --git a/toolbox/upstream-netbsd/usr.bin/grep/file.c b/toolbox/upstream-netbsd/usr.bin/grep/file.c
deleted file mode 100644
index cf4a0fa..0000000
--- a/toolbox/upstream-netbsd/usr.bin/grep/file.c
+++ /dev/null
@@ -1,271 +0,0 @@
-/* $NetBSD: file.c,v 1.7 2011/04/18 22:46:48 joerg Exp $ */
-/* $FreeBSD: head/usr.bin/grep/file.c 211496 2010-08-19 09:28:59Z des $ */
-/* $OpenBSD: file.c,v 1.11 2010/07/02 20:48:48 nicm Exp $ */
-
-/*-
- * Copyright (c) 1999 James Howard and Dag-Erling Coïdan Smørgrav
- * Copyright (C) 2008-2010 Gabor Kovesdan <gabor@FreeBSD.org>
- * Copyright (C) 2010 Dimitry Andric <dimitry@andric.com>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#if HAVE_NBTOOL_CONFIG_H
-#include "nbtool_config.h"
-#endif
-
-#include <sys/cdefs.h>
-__RCSID("$NetBSD: file.c,v 1.7 2011/04/18 22:46:48 joerg Exp $");
-
-#include <sys/param.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-
-#ifndef __ANDROID__
-#include <bzlib.h>
-#endif
-#include <err.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <stddef.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <wchar.h>
-#include <wctype.h>
-#ifndef __ANDROID__
-#include <zlib.h>
-#endif
-
-#include "grep.h"
-
-#define MAXBUFSIZ (32 * 1024)
-#define LNBUFBUMP 80
-
-#ifndef __ANDROID__
-static gzFile gzbufdesc;
-static BZFILE* bzbufdesc;
-#endif
-
-static unsigned char buffer[MAXBUFSIZ];
-static unsigned char *bufpos;
-static size_t bufrem;
-
-static unsigned char *lnbuf;
-static size_t lnbuflen;
-
-static inline int
-grep_refill(struct file *f)
-{
- ssize_t nr;
-#ifndef __ANDROID__
- int bzerr;
-#endif
-
- bufpos = buffer;
- bufrem = 0;
-
-#ifndef __ANDROID__
- if (filebehave == FILE_GZIP)
- nr = gzread(gzbufdesc, buffer, MAXBUFSIZ);
- else if (filebehave == FILE_BZIP && bzbufdesc != NULL) {
- nr = BZ2_bzRead(&bzerr, bzbufdesc, buffer, MAXBUFSIZ);
- switch (bzerr) {
- case BZ_OK:
- case BZ_STREAM_END:
- /* No problem, nr will be okay */
- break;
- case BZ_DATA_ERROR_MAGIC:
- /*
- * As opposed to gzread(), which simply returns the
- * plain file data, if it is not in the correct
- * compressed format, BZ2_bzRead() instead aborts.
- *
- * So, just restart at the beginning of the file again,
- * and use plain reads from now on.
- */
- BZ2_bzReadClose(&bzerr, bzbufdesc);
- bzbufdesc = NULL;
- if (lseek(f->fd, 0, SEEK_SET) == -1)
- return (-1);
- nr = read(f->fd, buffer, MAXBUFSIZ);
- break;
- default:
- /* Make sure we exit with an error */
- nr = -1;
- }
- } else
-#endif
- nr = read(f->fd, buffer, MAXBUFSIZ);
-
- if (nr < 0)
- return (-1);
-
- bufrem = nr;
- return (0);
-}
-
-static inline int
-grep_lnbufgrow(size_t newlen)
-{
-
- if (lnbuflen < newlen) {
- lnbuf = grep_realloc(lnbuf, newlen);
- lnbuflen = newlen;
- }
-
- return (0);
-}
-
-char *
-grep_fgetln(struct file *f, size_t *lenp)
-{
- unsigned char *p;
- char *ret;
- size_t len;
- size_t off;
- ptrdiff_t diff;
-
- /* Fill the buffer, if necessary */
- if (bufrem == 0 && grep_refill(f) != 0)
- goto error;
-
- if (bufrem == 0) {
- /* Return zero length to indicate EOF */
- *lenp = 0;
- return ((char *)bufpos);
- }
-
- /* Look for a newline in the remaining part of the buffer */
- if ((p = memchr(bufpos, line_sep, bufrem)) != NULL) {
- ++p; /* advance over newline */
- ret = (char *)bufpos;
- len = p - bufpos;
- bufrem -= len;
- bufpos = p;
- *lenp = len;
- return (ret);
- }
-
- /* We have to copy the current buffered data to the line buffer */
- for (len = bufrem, off = 0; ; len += bufrem) {
- /* Make sure there is room for more data */
- if (grep_lnbufgrow(len + LNBUFBUMP))
- goto error;
- memcpy(lnbuf + off, bufpos, len - off);
- off = len;
- if (grep_refill(f) != 0)
- goto error;
- if (bufrem == 0)
- /* EOF: return partial line */
- break;
- if ((p = memchr(bufpos, line_sep, bufrem)) == NULL)
- continue;
- /* got it: finish up the line (like code above) */
- ++p;
- diff = p - bufpos;
- len += diff;
- if (grep_lnbufgrow(len))
- goto error;
- memcpy(lnbuf + off, bufpos, diff);
- bufrem -= diff;
- bufpos = p;
- break;
- }
- *lenp = len;
- return ((char *)lnbuf);
-
-error:
- *lenp = 0;
- return (NULL);
-}
-
-static inline struct file *
-grep_file_init(struct file *f)
-{
-
-#ifndef __ANDROID__
- if (filebehave == FILE_GZIP &&
- (gzbufdesc = gzdopen(f->fd, "r")) == NULL)
- goto error;
-
- if (filebehave == FILE_BZIP &&
- (bzbufdesc = BZ2_bzdopen(f->fd, "r")) == NULL)
- goto error;
-#endif
-
- /* Fill read buffer, also catches errors early */
- if (grep_refill(f) != 0)
- goto error;
-
- /* Check for binary stuff, if necessary */
- if (!nulldataflag && binbehave != BINFILE_TEXT &&
- memchr(bufpos, '\0', bufrem) != NULL)
- f->binary = true;
-
- return (f);
-error:
- close(f->fd);
- free(f);
- return (NULL);
-}
-
-/*
- * Opens a file for processing.
- */
-struct file *
-grep_open(const char *path)
-{
- struct file *f;
-
- f = grep_malloc(sizeof *f);
- memset(f, 0, sizeof *f);
- if (path == NULL) {
- /* Processing stdin implies --line-buffered. */
- lbflag = true;
- f->fd = STDIN_FILENO;
- } else if ((f->fd = open(path, O_RDONLY)) == -1) {
- free(f);
- return (NULL);
- }
-
- return (grep_file_init(f));
-}
-
-/*
- * Closes a file.
- */
-void
-grep_close(struct file *f)
-{
-
- close(f->fd);
-
- /* Reset read buffer and line buffer */
- bufpos = buffer;
- bufrem = 0;
-
- free(lnbuf);
- lnbuf = NULL;
- lnbuflen = 0;
-}
diff --git a/toolbox/upstream-netbsd/usr.bin/grep/grep.c b/toolbox/upstream-netbsd/usr.bin/grep/grep.c
deleted file mode 100644
index 1ea6ed3..0000000
--- a/toolbox/upstream-netbsd/usr.bin/grep/grep.c
+++ /dev/null
@@ -1,707 +0,0 @@
-/* $NetBSD: grep.c,v 1.12 2014/07/11 16:30:45 christos Exp $ */
-/* $FreeBSD: head/usr.bin/grep/grep.c 211519 2010-08-19 22:55:17Z delphij $ */
-/* $OpenBSD: grep.c,v 1.42 2010/07/02 22:18:03 tedu Exp $ */
-
-/*-
- * Copyright (c) 1999 James Howard and Dag-Erling Coïdan Smørgrav
- * Copyright (C) 2008-2009 Gabor Kovesdan <gabor@FreeBSD.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#if HAVE_NBTOOL_CONFIG_H
-#include "nbtool_config.h"
-#endif
-
-#include <sys/cdefs.h>
-__RCSID("$NetBSD: grep.c,v 1.12 2014/07/11 16:30:45 christos Exp $");
-
-#include <sys/stat.h>
-#include <sys/types.h>
-
-#include <ctype.h>
-#include <err.h>
-#include <errno.h>
-#include <getopt.h>
-#include <limits.h>
-#include <libgen.h>
-#include <locale.h>
-#include <stdbool.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-
-#include "grep.h"
-
-#ifndef WITHOUT_NLS
-#include <nl_types.h>
-nl_catd catalog;
-#endif
-
-/*
- * Default messags to use when NLS is disabled or no catalogue
- * is found.
- */
-const char *errstr[] = {
- "",
-/* 1*/ "(standard input)",
-/* 2*/ "cannot read bzip2 compressed file",
-/* 3*/ "unknown %s option",
-/* 4*/ "usage: %s [-abcDEFGHhIiJLlmnOoPqRSsUVvwxZz] [-A num] [-B num] [-C[num]]\n",
-/* 5*/ "\t[-e pattern] [-f file] [--binary-files=value] [--color=when]\n",
-/* 6*/ "\t[--context[=num]] [--directories=action] [--label] [--line-buffered]\n",
-/* 7*/ "\t[pattern] [file ...]\n",
-/* 8*/ "Binary file %s matches\n",
-/* 9*/ "%s (BSD grep) %s\n",
-};
-
-/* Flags passed to regcomp() and regexec() */
-int cflags = 0;
-int eflags = REG_STARTEND;
-
-/* Searching patterns */
-unsigned int patterns, pattern_sz;
-char **pattern;
-regex_t *r_pattern;
-fastgrep_t *fg_pattern;
-
-/* Filename exclusion/inclusion patterns */
-unsigned int fpatterns, fpattern_sz;
-unsigned int dpatterns, dpattern_sz;
-struct epat *dpattern, *fpattern;
-
-/* For regex errors */
-char re_error[RE_ERROR_BUF + 1];
-
-/* Command-line flags */
-unsigned long long Aflag; /* -A x: print x lines trailing each match */
-unsigned long long Bflag; /* -B x: print x lines leading each match */
-bool Hflag; /* -H: always print file name */
-bool Lflag; /* -L: only show names of files with no matches */
-bool bflag; /* -b: show block numbers for each match */
-bool cflag; /* -c: only show a count of matching lines */
-bool hflag; /* -h: don't print filename headers */
-bool iflag; /* -i: ignore case */
-bool lflag; /* -l: only show names of files with matches */
-bool mflag; /* -m x: stop reading the files after x matches */
-unsigned long long mcount; /* count for -m */
-bool nflag; /* -n: show line numbers in front of matching lines */
-bool oflag; /* -o: print only matching part */
-bool qflag; /* -q: quiet mode (don't output anything) */
-bool sflag; /* -s: silent mode (ignore errors) */
-bool vflag; /* -v: only show non-matching lines */
-bool wflag; /* -w: pattern must start and end on word boundaries */
-bool xflag; /* -x: pattern must match entire line */
-bool lbflag; /* --line-buffered */
-bool nullflag; /* --null */
-bool nulldataflag; /* --null-data */
-unsigned char line_sep = '\n'; /* 0 for --null-data */
-char *label; /* --label */
-const char *color; /* --color */
-int grepbehave = GREP_BASIC; /* -EFGP: type of the regex */
-int binbehave = BINFILE_BIN; /* -aIU: handling of binary files */
-int filebehave = FILE_STDIO; /* -JZ: normal, gzip or bzip2 file */
-int devbehave = DEV_READ; /* -D: handling of devices */
-int dirbehave = DIR_READ; /* -dRr: handling of directories */
-int linkbehave = LINK_READ; /* -OpS: handling of symlinks */
-
-bool dexclude, dinclude; /* --exclude-dir and --include-dir */
-bool fexclude, finclude; /* --exclude and --include */
-
-enum {
- BIN_OPT = CHAR_MAX + 1,
- COLOR_OPT,
- DECOMPRESS_OPT,
- HELP_OPT,
- MMAP_OPT,
- LINEBUF_OPT,
- LABEL_OPT,
- R_EXCLUDE_OPT,
- R_INCLUDE_OPT,
- R_DEXCLUDE_OPT,
- R_DINCLUDE_OPT
-};
-
-static inline const char *init_color(const char *);
-
-/* Housekeeping */
-int tail; /* lines left to print */
-bool notfound; /* file not found */
-
-extern char *__progname;
-
-/*
- * Prints usage information and returns 2.
- */
-__dead static void
-usage(void)
-{
- fprintf(stderr, getstr(4), __progname);
- fprintf(stderr, "%s", getstr(5));
- fprintf(stderr, "%s", getstr(6));
- fprintf(stderr, "%s", getstr(7));
- exit(2);
-}
-
-static const char optstr[] =
- "0123456789A:B:C:D:EFGHIJLOPSRUVZabcd:e:f:hilm:nopqrsuvwxyz";
-
-struct option long_options[] =
-{
- {"binary-files", required_argument, NULL, BIN_OPT},
- {"decompress", no_argument, NULL, DECOMPRESS_OPT},
- {"help", no_argument, NULL, HELP_OPT},
- {"mmap", no_argument, NULL, MMAP_OPT},
- {"line-buffered", no_argument, NULL, LINEBUF_OPT},
- {"label", required_argument, NULL, LABEL_OPT},
- {"color", optional_argument, NULL, COLOR_OPT},
- {"colour", optional_argument, NULL, COLOR_OPT},
- {"exclude", required_argument, NULL, R_EXCLUDE_OPT},
- {"include", required_argument, NULL, R_INCLUDE_OPT},
- {"exclude-dir", required_argument, NULL, R_DEXCLUDE_OPT},
- {"include-dir", required_argument, NULL, R_DINCLUDE_OPT},
- {"after-context", required_argument, NULL, 'A'},
- {"text", no_argument, NULL, 'a'},
- {"before-context", required_argument, NULL, 'B'},
- {"byte-offset", no_argument, NULL, 'b'},
- {"context", optional_argument, NULL, 'C'},
- {"count", no_argument, NULL, 'c'},
- {"devices", required_argument, NULL, 'D'},
- {"directories", required_argument, NULL, 'd'},
- {"extended-regexp", no_argument, NULL, 'E'},
- {"regexp", required_argument, NULL, 'e'},
- {"fixed-strings", no_argument, NULL, 'F'},
- {"file", required_argument, NULL, 'f'},
- {"basic-regexp", no_argument, NULL, 'G'},
- {"no-filename", no_argument, NULL, 'h'},
- {"with-filename", no_argument, NULL, 'H'},
- {"ignore-case", no_argument, NULL, 'i'},
- {"bz2decompress", no_argument, NULL, 'J'},
- {"files-with-matches", no_argument, NULL, 'l'},
- {"files-without-match", no_argument, NULL, 'L'},
- {"max-count", required_argument, NULL, 'm'},
- {"line-number", no_argument, NULL, 'n'},
- {"only-matching", no_argument, NULL, 'o'},
- {"quiet", no_argument, NULL, 'q'},
- {"silent", no_argument, NULL, 'q'},
- {"recursive", no_argument, NULL, 'r'},
- {"no-messages", no_argument, NULL, 's'},
- {"binary", no_argument, NULL, 'U'},
- {"unix-byte-offsets", no_argument, NULL, 'u'},
- {"invert-match", no_argument, NULL, 'v'},
- {"version", no_argument, NULL, 'V'},
- {"word-regexp", no_argument, NULL, 'w'},
- {"line-regexp", no_argument, NULL, 'x'},
- {"null", no_argument, NULL, 'Z'},
- {"null-data", no_argument, NULL, 'z'},
- {NULL, no_argument, NULL, 0}
-};
-
-/*
- * Adds a searching pattern to the internal array.
- */
-static void
-add_pattern(char *pat, size_t len)
-{
-
- /* TODO: Check for empty patterns and shortcut */
-
- /* Increase size if necessary */
- if (patterns == pattern_sz) {
- pattern_sz *= 2;
- pattern = grep_realloc(pattern, ++pattern_sz *
- sizeof(*pattern));
- }
- if (len > 0 && pat[len - 1] == '\n')
- --len;
- /* pat may not be NUL-terminated */
- pattern[patterns] = grep_malloc(len + 1);
- memcpy(pattern[patterns], pat, len);
- pattern[patterns][len] = '\0';
- ++patterns;
-}
-
-/*
- * Adds a file include/exclude pattern to the internal array.
- */
-static void
-add_fpattern(const char *pat, int mode)
-{
-
- /* Increase size if necessary */
- if (fpatterns == fpattern_sz) {
- fpattern_sz *= 2;
- fpattern = grep_realloc(fpattern, ++fpattern_sz *
- sizeof(struct epat));
- }
- fpattern[fpatterns].pat = grep_strdup(pat);
- fpattern[fpatterns].mode = mode;
- ++fpatterns;
-}
-
-/*
- * Adds a directory include/exclude pattern to the internal array.
- */
-static void
-add_dpattern(const char *pat, int mode)
-{
-
- /* Increase size if necessary */
- if (dpatterns == dpattern_sz) {
- dpattern_sz *= 2;
- dpattern = grep_realloc(dpattern, ++dpattern_sz *
- sizeof(struct epat));
- }
- dpattern[dpatterns].pat = grep_strdup(pat);
- dpattern[dpatterns].mode = mode;
- ++dpatterns;
-}
-
-/*
- * Reads searching patterns from a file and adds them with add_pattern().
- */
-static void
-read_patterns(const char *fn)
-{
- FILE *f;
- char *line;
- size_t len;
- ssize_t rlen;
-
- if ((f = fopen(fn, "r")) == NULL)
- err(2, "%s", fn);
- line = NULL;
- len = 0;
- while ((rlen = getline(&line, &len, f)) != -1)
- add_pattern(line, *line == '\n' ? 0 : (size_t)rlen);
- free(line);
- if (ferror(f))
- err(2, "%s", fn);
- fclose(f);
-}
-
-static inline const char *
-init_color(const char *d)
-{
- char *c;
-
- c = getenv("GREP_COLOR");
- return (c != NULL ? c : d);
-}
-
-int
-main(int argc, char *argv[])
-{
- char **aargv, **eargv, *eopts;
- char *ep;
- unsigned long long l;
- unsigned int aargc, eargc, i, j;
- int c, lastc, needpattern, newarg, prevoptind;
-
- setlocale(LC_ALL, "");
-
-#ifndef WITHOUT_NLS
- catalog = catopen("grep", NL_CAT_LOCALE);
-#endif
-
- /* Check what is the program name of the binary. In this
- way we can have all the funcionalities in one binary
- without the need of scripting and using ugly hacks. */
- switch (__progname[0]) {
- case 'e':
- grepbehave = GREP_EXTENDED;
- break;
- case 'f':
- grepbehave = GREP_FIXED;
- break;
- case 'g':
- grepbehave = GREP_BASIC;
- break;
- case 'z':
- filebehave = FILE_GZIP;
- switch(__progname[1]) {
- case 'e':
- grepbehave = GREP_EXTENDED;
- break;
- case 'f':
- grepbehave = GREP_FIXED;
- break;
- case 'g':
- grepbehave = GREP_BASIC;
- break;
- }
- break;
- }
-
- lastc = '\0';
- newarg = 1;
- prevoptind = 1;
- needpattern = 1;
-
- eopts = getenv("GREP_OPTIONS");
-
- /* support for extra arguments in GREP_OPTIONS */
- eargc = 0;
- if (eopts != NULL) {
- char *str;
-
- /* make an estimation of how many extra arguments we have */
- for (j = 0; j < strlen(eopts); j++)
- if (eopts[j] == ' ')
- eargc++;
-
- eargv = (char **)grep_malloc(sizeof(char *) * (eargc + 1));
-
- eargc = 0;
- /* parse extra arguments */
- while ((str = strsep(&eopts, " ")) != NULL)
- eargv[eargc++] = grep_strdup(str);
-
- aargv = (char **)grep_calloc(eargc + argc + 1,
- sizeof(char *));
-
- aargv[0] = argv[0];
- for (i = 0; i < eargc; i++)
- aargv[i + 1] = eargv[i];
- for (j = 1; j < (unsigned int)argc; j++, i++)
- aargv[i + 1] = argv[j];
-
- aargc = eargc + argc;
- } else {
- aargv = argv;
- aargc = argc;
- }
-
- while (((c = getopt_long(aargc, aargv, optstr, long_options, NULL)) !=
- -1)) {
- switch (c) {
- case '0': case '1': case '2': case '3': case '4':
- case '5': case '6': case '7': case '8': case '9':
- if (newarg || !isdigit(lastc))
- Aflag = 0;
- else if (Aflag > LLONG_MAX / 10) {
- errno = ERANGE;
- err(2, NULL);
- }
- Aflag = Bflag = (Aflag * 10) + (c - '0');
- break;
- case 'C':
- if (optarg == NULL) {
- Aflag = Bflag = 2;
- break;
- }
- /* FALLTHROUGH */
- case 'A':
- /* FALLTHROUGH */
- case 'B':
- errno = 0;
- l = strtoull(optarg, &ep, 10);
- if (((errno == ERANGE) && (l == ULLONG_MAX)) ||
- ((errno == EINVAL) && (l == 0)))
- err(2, NULL);
- else if (ep[0] != '\0') {
- errno = EINVAL;
- err(2, NULL);
- }
- if (c == 'A')
- Aflag = l;
- else if (c == 'B')
- Bflag = l;
- else
- Aflag = Bflag = l;
- break;
- case 'a':
- binbehave = BINFILE_TEXT;
- break;
- case 'b':
- bflag = true;
- break;
- case 'c':
- cflag = true;
- break;
- case 'D':
- if (strcasecmp(optarg, "skip") == 0)
- devbehave = DEV_SKIP;
- else if (strcasecmp(optarg, "read") == 0)
- devbehave = DEV_READ;
- else
- errx(2, getstr(3), "--devices");
- break;
- case 'd':
- if (strcasecmp("recurse", optarg) == 0) {
- Hflag = true;
- dirbehave = DIR_RECURSE;
- } else if (strcasecmp("skip", optarg) == 0)
- dirbehave = DIR_SKIP;
- else if (strcasecmp("read", optarg) == 0)
- dirbehave = DIR_READ;
- else
- errx(2, getstr(3), "--directories");
- break;
- case 'E':
- grepbehave = GREP_EXTENDED;
- break;
- case 'e':
- add_pattern(optarg, strlen(optarg));
- needpattern = 0;
- break;
- case 'F':
- grepbehave = GREP_FIXED;
- break;
- case 'f':
- read_patterns(optarg);
- needpattern = 0;
- break;
- case 'G':
- grepbehave = GREP_BASIC;
- break;
- case 'H':
- Hflag = true;
- break;
- case 'h':
- Hflag = false;
- hflag = true;
- break;
- case 'I':
- binbehave = BINFILE_SKIP;
- break;
- case 'i':
- case 'y':
- iflag = true;
- cflags |= REG_ICASE;
- break;
- case 'J':
- filebehave = FILE_BZIP;
- break;
- case 'L':
- lflag = false;
- Lflag = true;
- break;
- case 'l':
- Lflag = false;
- lflag = true;
- break;
- case 'm':
- mflag = true;
- errno = 0;
- mcount = strtoull(optarg, &ep, 10);
- if (((errno == ERANGE) && (mcount == ULLONG_MAX)) ||
- ((errno == EINVAL) && (mcount == 0)))
- err(2, NULL);
- else if (ep[0] != '\0') {
- errno = EINVAL;
- err(2, NULL);
- }
- break;
- case 'n':
- nflag = true;
- break;
- case 'O':
- linkbehave = LINK_EXPLICIT;
- break;
- case 'o':
- oflag = true;
- break;
- case 'p':
- linkbehave = LINK_SKIP;
- break;
- case 'q':
- qflag = true;
- break;
- case 'S':
- linkbehave = LINK_READ;
- break;
- case 'R':
- case 'r':
- dirbehave = DIR_RECURSE;
- Hflag = true;
- break;
- case 's':
- sflag = true;
- break;
- case 'U':
- binbehave = BINFILE_BIN;
- break;
- case 'u':
- case MMAP_OPT:
- /* noop, compatibility */
- break;
- case 'V':
- printf(getstr(9), __progname, VERSION);
- exit(0);
- case 'v':
- vflag = true;
- break;
- case 'w':
- wflag = true;
- break;
- case 'x':
- xflag = true;
- break;
- case 'Z':
- nullflag = true;
- break;
- case 'z':
- nulldataflag = true;
- line_sep = '\0';
- break;
- case BIN_OPT:
- if (strcasecmp("binary", optarg) == 0)
- binbehave = BINFILE_BIN;
- else if (strcasecmp("without-match", optarg) == 0)
- binbehave = BINFILE_SKIP;
- else if (strcasecmp("text", optarg) == 0)
- binbehave = BINFILE_TEXT;
- else
- errx(2, getstr(3), "--binary-files");
- break;
- case COLOR_OPT:
- color = NULL;
- if (optarg == NULL || strcasecmp("auto", optarg) == 0 ||
- strcasecmp("tty", optarg) == 0 ||
- strcasecmp("if-tty", optarg) == 0) {
- char *term;
-
- term = getenv("TERM");
- if (isatty(STDOUT_FILENO) && term != NULL &&
- strcasecmp(term, "dumb") != 0)
- color = init_color("01;31");
- } else if (strcasecmp("always", optarg) == 0 ||
- strcasecmp("yes", optarg) == 0 ||
- strcasecmp("force", optarg) == 0) {
- color = init_color("01;31");
- } else if (strcasecmp("never", optarg) != 0 &&
- strcasecmp("none", optarg) != 0 &&
- strcasecmp("no", optarg) != 0)
- errx(2, getstr(3), "--color");
- break;
- case DECOMPRESS_OPT:
- filebehave = FILE_GZIP;
- break;
- case LABEL_OPT:
- label = optarg;
- break;
- case LINEBUF_OPT:
- lbflag = true;
- break;
- case R_INCLUDE_OPT:
- finclude = true;
- add_fpattern(optarg, INCL_PAT);
- break;
- case R_EXCLUDE_OPT:
- fexclude = true;
- add_fpattern(optarg, EXCL_PAT);
- break;
- case R_DINCLUDE_OPT:
- dinclude = true;
- add_dpattern(optarg, INCL_PAT);
- break;
- case R_DEXCLUDE_OPT:
- dexclude = true;
- add_dpattern(optarg, EXCL_PAT);
- break;
- case HELP_OPT:
- default:
- usage();
- }
- lastc = c;
- newarg = optind != prevoptind;
- prevoptind = optind;
- }
- aargc -= optind;
- aargv += optind;
-
- /* Fail if we don't have any pattern */
- if (aargc == 0 && needpattern)
- usage();
-
- /* Process patterns from command line */
- if (aargc != 0 && needpattern) {
- add_pattern(*aargv, strlen(*aargv));
- --aargc;
- ++aargv;
- }
-
- switch (grepbehave) {
- case GREP_FIXED:
- case GREP_BASIC:
- break;
- case GREP_EXTENDED:
- cflags |= REG_EXTENDED;
- break;
- default:
- /* NOTREACHED */
- usage();
- }
-
- fg_pattern = grep_calloc(patterns, sizeof(*fg_pattern));
- r_pattern = grep_calloc(patterns, sizeof(*r_pattern));
-/*
- * XXX: fgrepcomp() and fastcomp() are workarounds for regexec() performance.
- * Optimizations should be done there.
- */
- /* Check if cheating is allowed (always is for fgrep). */
- if (grepbehave == GREP_FIXED) {
- for (i = 0; i < patterns; ++i)
- fgrepcomp(&fg_pattern[i], pattern[i]);
- } else {
- for (i = 0; i < patterns; ++i) {
- if (fastcomp(&fg_pattern[i], pattern[i])) {
- /* Fall back to full regex library */
- c = regcomp(&r_pattern[i], pattern[i], cflags);
- if (c != 0) {
- regerror(c, &r_pattern[i], re_error,
- RE_ERROR_BUF);
- errx(2, "%s", re_error);
- }
- }
- }
- }
-
- if (lbflag)
- setlinebuf(stdout);
-
- if ((aargc == 0 || aargc == 1) && !Hflag)
- hflag = true;
-
- if (aargc == 0)
- exit(!procfile("-"));
-
- if (dirbehave == DIR_RECURSE)
- c = grep_tree(aargv);
- else
- for (c = 0; aargc--; ++aargv) {
- if ((finclude || fexclude) && !file_matching(*aargv))
- continue;
- c+= procfile(*aargv);
- }
-
-#ifndef WITHOUT_NLS
- catclose(catalog);
-#endif
-
- /* Find out the correct return value according to the
- results and the command line option. */
- exit(c ? (notfound ? (qflag ? 0 : 2) : 0) : (notfound ? 2 : 1));
-}
diff --git a/toolbox/upstream-netbsd/usr.bin/grep/grep.h b/toolbox/upstream-netbsd/usr.bin/grep/grep.h
deleted file mode 100644
index fa2a3e3..0000000
--- a/toolbox/upstream-netbsd/usr.bin/grep/grep.h
+++ /dev/null
@@ -1,162 +0,0 @@
-/* $NetBSD: grep.h,v 1.8 2012/05/06 22:27:00 joerg Exp $ */
-/* $OpenBSD: grep.h,v 1.15 2010/04/05 03:03:55 tedu Exp $ */
-/* $FreeBSD: head/usr.bin/grep/grep.h 211496 2010-08-19 09:28:59Z des $ */
-
-/*-
- * Copyright (c) 1999 James Howard and Dag-Erling Coïdan Smørgrav
- * Copyright (c) 2008-2009 Gabor Kovesdan <gabor@FreeBSD.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#ifndef __ANDROID__
-#include <bzlib.h>
-#endif
-#include <limits.h>
-#include <regex.h>
-#include <stdbool.h>
-#include <stdio.h>
-#ifndef __ANDROID__
-#include <zlib.h>
-#endif
-
-#ifdef WITHOUT_NLS
-#define getstr(n) errstr[n]
-#else
-#include <nl_types.h>
-
-extern nl_catd catalog;
-#define getstr(n) catgets(catalog, 1, n, errstr[n])
-#endif
-
-extern const char *errstr[];
-
-#define VERSION "2.5.1-FreeBSD"
-
-#define GREP_FIXED 0
-#define GREP_BASIC 1
-#define GREP_EXTENDED 2
-
-#define BINFILE_BIN 0
-#define BINFILE_SKIP 1
-#define BINFILE_TEXT 2
-
-#define FILE_STDIO 0
-#define FILE_GZIP 1
-#define FILE_BZIP 2
-
-#define DIR_READ 0
-#define DIR_SKIP 1
-#define DIR_RECURSE 2
-
-#define DEV_READ 0
-#define DEV_SKIP 1
-
-#define LINK_READ 0
-#define LINK_EXPLICIT 1
-#define LINK_SKIP 2
-
-#define EXCL_PAT 0
-#define INCL_PAT 1
-
-#define MAX_LINE_MATCHES 32
-
-struct file {
- int fd;
- bool binary;
-};
-
-struct str {
- off_t off;
- size_t len;
- char *dat;
- char *file;
- int line_no;
-};
-
-struct epat {
- char *pat;
- int mode;
-};
-
-typedef struct {
- size_t len;
- unsigned char *pattern;
- int qsBc[UCHAR_MAX + 1];
- /* flags */
- bool bol;
- bool eol;
- bool reversed;
- bool word;
-} fastgrep_t;
-
-/* Flags passed to regcomp() and regexec() */
-extern int cflags, eflags;
-
-/* Command line flags */
-extern bool Eflag, Fflag, Gflag, Hflag, Lflag,
- bflag, cflag, hflag, iflag, lflag, mflag, nflag, oflag,
- qflag, sflag, vflag, wflag, xflag;
-extern bool dexclude, dinclude, fexclude, finclude, lbflag, nullflag, nulldataflag;
-extern unsigned char line_sep;
-extern unsigned long long Aflag, Bflag, mcount;
-extern char *label;
-extern const char *color;
-extern int binbehave, devbehave, dirbehave, filebehave, grepbehave, linkbehave;
-
-extern bool notfound;
-extern int tail;
-extern unsigned int dpatterns, fpatterns, patterns;
-extern char **pattern;
-extern struct epat *dpattern, *fpattern;
-extern regex_t *er_pattern, *r_pattern;
-extern fastgrep_t *fg_pattern;
-
-/* For regex errors */
-#define RE_ERROR_BUF 512
-extern char re_error[RE_ERROR_BUF + 1]; /* Seems big enough */
-
-/* util.c */
-bool file_matching(const char *fname);
-int procfile(const char *fn);
-int grep_tree(char **argv);
-void *grep_malloc(size_t size);
-void *grep_calloc(size_t nmemb, size_t size);
-void *grep_realloc(void *ptr, size_t size);
-char *grep_strdup(const char *str);
-void printline(struct str *line, int sep, regmatch_t *matches, int m);
-
-/* queue.c */
-void enqueue(struct str *x);
-void printqueue(void);
-void clearqueue(void);
-
-/* file.c */
-void grep_close(struct file *f);
-struct file *grep_open(const char *path);
-char *grep_fgetln(struct file *f, size_t *len);
-
-/* fastgrep.c */
-int fastcomp(fastgrep_t *, const char *);
-void fgrepcomp(fastgrep_t *, const char *);
-int grep_search(fastgrep_t *, const unsigned char *, size_t, regmatch_t *);
diff --git a/toolbox/upstream-netbsd/usr.bin/grep/queue.c b/toolbox/upstream-netbsd/usr.bin/grep/queue.c
deleted file mode 100644
index e3c6be1..0000000
--- a/toolbox/upstream-netbsd/usr.bin/grep/queue.c
+++ /dev/null
@@ -1,116 +0,0 @@
-/* $NetBSD: queue.c,v 1.5 2011/08/31 16:24:57 plunky Exp $ */
-/* $FreeBSD: head/usr.bin/grep/queue.c 211496 2010-08-19 09:28:59Z des $ */
-/*-
- * Copyright (c) 1999 James Howard and Dag-Erling Coïdan Smørgrav
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-/*
- * A really poor man's queue. It does only what it has to and gets out of
- * Dodge. It is used in place of <sys/queue.h> to get a better performance.
- */
-
-#if HAVE_NBTOOL_CONFIG_H
-#include "nbtool_config.h"
-#endif
-
-#include <sys/cdefs.h>
-__RCSID("$NetBSD: queue.c,v 1.5 2011/08/31 16:24:57 plunky Exp $");
-
-#include <sys/param.h>
-#include <sys/queue.h>
-
-#include <stdlib.h>
-#include <string.h>
-
-#include "grep.h"
-
-struct qentry {
- STAILQ_ENTRY(qentry) list;
- struct str data;
-};
-
-static STAILQ_HEAD(, qentry) queue = STAILQ_HEAD_INITIALIZER(queue);
-static unsigned long long count;
-
-static struct qentry *dequeue(void);
-
-void
-enqueue(struct str *x)
-{
- struct qentry *item;
-
- item = grep_malloc(sizeof(struct qentry));
- item->data.dat = grep_malloc(sizeof(char) * x->len);
- item->data.len = x->len;
- item->data.line_no = x->line_no;
- item->data.off = x->off;
- memcpy(item->data.dat, x->dat, x->len);
- item->data.file = x->file;
-
- STAILQ_INSERT_TAIL(&queue, item, list);
-
- if (++count > Bflag) {
- item = dequeue();
- free(item->data.dat);
- free(item);
- }
-}
-
-static struct qentry *
-dequeue(void)
-{
- struct qentry *item;
-
- item = STAILQ_FIRST(&queue);
- if (item == NULL)
- return (NULL);
-
- STAILQ_REMOVE_HEAD(&queue, list);
- --count;
- return (item);
-}
-
-void
-printqueue(void)
-{
- struct qentry *item;
-
- while ((item = dequeue()) != NULL) {
- printline(&item->data, '-', NULL, 0);
- free(item->data.dat);
- free(item);
- }
-}
-
-void
-clearqueue(void)
-{
- struct qentry *item;
-
- while ((item = dequeue()) != NULL) {
- free(item->data.dat);
- free(item);
- }
-}
diff --git a/toolbox/upstream-netbsd/usr.bin/grep/util.c b/toolbox/upstream-netbsd/usr.bin/grep/util.c
deleted file mode 100644
index ecd948d..0000000
--- a/toolbox/upstream-netbsd/usr.bin/grep/util.c
+++ /dev/null
@@ -1,499 +0,0 @@
-/* $NetBSD: util.c,v 1.17 2013/01/21 03:24:43 msaitoh Exp $ */
-/* $FreeBSD: head/usr.bin/grep/util.c 211496 2010-08-19 09:28:59Z des $ */
-/* $OpenBSD: util.c,v 1.39 2010/07/02 22:18:03 tedu Exp $ */
-
-/*-
- * Copyright (c) 1999 James Howard and Dag-Erling Coïdan Smørgrav
- * Copyright (C) 2008-2010 Gabor Kovesdan <gabor@FreeBSD.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#if HAVE_NBTOOL_CONFIG_H
-#include "nbtool_config.h"
-#endif
-
-#include <sys/cdefs.h>
-__RCSID("$NetBSD: util.c,v 1.17 2013/01/21 03:24:43 msaitoh Exp $");
-
-#include <sys/stat.h>
-#include <sys/types.h>
-
-#include <ctype.h>
-#include <err.h>
-#include <errno.h>
-#include <fnmatch.h>
-#include <fts.h>
-#include <libgen.h>
-#include <stdbool.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <wchar.h>
-#include <wctype.h>
-
-#include "grep.h"
-
-static bool first, first_global = true;
-static unsigned long long since_printed;
-
-static int procline(struct str *l, int);
-
-bool
-file_matching(const char *fname)
-{
- char *fname_base, *fname_copy;
- unsigned int i;
- bool ret;
-
- ret = finclude ? false : true;
- fname_copy = grep_strdup(fname);
- fname_base = basename(fname_copy);
-
- for (i = 0; i < fpatterns; ++i) {
- if (fnmatch(fpattern[i].pat, fname, 0) == 0 ||
- fnmatch(fpattern[i].pat, fname_base, 0) == 0) {
- if (fpattern[i].mode == EXCL_PAT) {
- free(fname_copy);
- return (false);
- } else
- ret = true;
- }
- }
- free(fname_copy);
- return (ret);
-}
-
-static inline bool
-dir_matching(const char *dname)
-{
- unsigned int i;
- bool ret;
-
- ret = dinclude ? false : true;
-
- for (i = 0; i < dpatterns; ++i) {
- if (dname != NULL &&
- fnmatch(dname, dpattern[i].pat, 0) == 0) {
- if (dpattern[i].mode == EXCL_PAT)
- return (false);
- else
- ret = true;
- }
- }
- return (ret);
-}
-
-/*
- * Processes a directory when a recursive search is performed with
- * the -R option. Each appropriate file is passed to procfile().
- */
-int
-grep_tree(char **argv)
-{
- FTS *fts;
- FTSENT *p;
- char *d, *dir = NULL;
- int c, fts_flags;
- bool ok;
-
- c = fts_flags = 0;
-
- switch(linkbehave) {
- case LINK_EXPLICIT:
- fts_flags = FTS_COMFOLLOW;
- break;
- case LINK_SKIP:
- fts_flags = FTS_PHYSICAL;
- break;
- default:
- fts_flags = FTS_LOGICAL;
-
- }
-
- fts_flags |= FTS_NOSTAT | FTS_NOCHDIR;
-
- if (!(fts = fts_open(argv, fts_flags, NULL)))
- err(2, "fts_open");
- while ((p = fts_read(fts)) != NULL) {
- switch (p->fts_info) {
- case FTS_DNR:
- /* FALLTHROUGH */
- case FTS_ERR:
- errx(2, "%s: %s", p->fts_path, strerror(p->fts_errno));
- break;
- case FTS_D:
- /* FALLTHROUGH */
- case FTS_DP:
- break;
- case FTS_DC:
- /* Print a warning for recursive directory loop */
- warnx("warning: %s: recursive directory loop",
- p->fts_path);
- break;
- default:
- /* Check for file exclusion/inclusion */
- ok = true;
- if (dexclude || dinclude) {
- if ((d = strrchr(p->fts_path, '/')) != NULL) {
- dir = grep_malloc(sizeof(char) *
- (d - p->fts_path + 1));
- memcpy(dir, p->fts_path,
- d - p->fts_path);
- dir[d - p->fts_path] = '\0';
- }
- ok = dir_matching(dir);
- free(dir);
- dir = NULL;
- }
- if (fexclude || finclude)
- ok &= file_matching(p->fts_path);
-
- if (ok)
- c += procfile(p->fts_path);
- break;
- }
- }
-
- fts_close(fts);
- return (c);
-}
-
-/*
- * Opens a file and processes it. Each file is processed line-by-line
- * passing the lines to procline().
- */
-int
-procfile(const char *fn)
-{
- struct file *f;
- struct stat sb;
- struct str ln;
- mode_t s;
- int c, t;
-
- if (mflag && (mcount <= 0))
- return (0);
-
- if (strcmp(fn, "-") == 0) {
- fn = label != NULL ? label : getstr(1);
- f = grep_open(NULL);
- } else {
- if (!stat(fn, &sb)) {
- /* Check if we need to process the file */
- s = sb.st_mode & S_IFMT;
- if (s == S_IFDIR && dirbehave == DIR_SKIP)
- return (0);
- if ((s == S_IFIFO || s == S_IFCHR || s == S_IFBLK
- || s == S_IFSOCK) && devbehave == DEV_SKIP)
- return (0);
- }
- f = grep_open(fn);
- }
- if (f == NULL) {
- if (!sflag)
- warn("%s", fn);
- if (errno == ENOENT)
- notfound = true;
- return (0);
- }
-
- ln.file = grep_malloc(strlen(fn) + 1);
- strcpy(ln.file, fn);
- ln.line_no = 0;
- ln.len = 0;
- tail = 0;
- ln.off = -1;
-
- for (first = true, c = 0; c == 0 || !(lflag || qflag); ) {
- ln.off += ln.len + 1;
- if ((ln.dat = grep_fgetln(f, &ln.len)) == NULL || ln.len == 0)
- break;
- if (ln.len > 0 && ln.dat[ln.len - 1] == line_sep)
- --ln.len;
- ln.line_no++;
-
- /* Return if we need to skip a binary file */
- if (f->binary && binbehave == BINFILE_SKIP) {
- grep_close(f);
- free(ln.file);
- free(f);
- return (0);
- }
- /* Process the file line-by-line */
- t = procline(&ln, f->binary);
- c += t;
-
- /* Count the matches if we have a match limit */
- if (mflag) {
- mcount -= t;
- if (mcount <= 0)
- break;
- }
- }
- if (Bflag > 0)
- clearqueue();
- grep_close(f);
-
- if (cflag) {
- if (!hflag)
- printf("%s:", ln.file);
- printf("%u%c", c, line_sep);
- }
- if (lflag && !qflag && c != 0)
- printf("%s%c", fn, line_sep);
- if (Lflag && !qflag && c == 0)
- printf("%s%c", fn, line_sep);
- if (c && !cflag && !lflag && !Lflag &&
- binbehave == BINFILE_BIN && f->binary && !qflag)
- printf(getstr(8), fn);
-
- free(ln.file);
- free(f);
- return (c);
-}
-
-#define iswword(x) (iswalnum((x)) || (x) == L'_')
-
-/*
- * Processes a line comparing it with the specified patterns. Each pattern
- * is looped to be compared along with the full string, saving each and every
- * match, which is necessary to colorize the output and to count the
- * matches. The matching lines are passed to printline() to display the
- * appropriate output.
- */
-static int
-procline(struct str *l, int nottext)
-{
- regmatch_t matches[MAX_LINE_MATCHES];
- regmatch_t pmatch;
- size_t st = 0;
- unsigned int i;
- int c = 0, m = 0, r = 0;
-
- /* Loop to process the whole line */
- while (st <= l->len) {
- pmatch.rm_so = st;
- pmatch.rm_eo = l->len;
-
- /* Loop to compare with all the patterns */
- for (i = 0; i < patterns; i++) {
-/*
- * XXX: grep_search() is a workaround for speed up and should be
- * removed in the future. See fastgrep.c.
- */
- if (fg_pattern[i].pattern) {
- r = grep_search(&fg_pattern[i],
- (unsigned char *)l->dat,
- l->len, &pmatch);
- r = (r == 0) ? 0 : REG_NOMATCH;
- st = pmatch.rm_eo;
- } else {
- r = regexec(&r_pattern[i], l->dat, 1,
- &pmatch, eflags);
- r = (r == 0) ? 0 : REG_NOMATCH;
- st = pmatch.rm_eo;
- }
- if (r == REG_NOMATCH)
- continue;
- /* Check for full match */
- if (xflag &&
- (pmatch.rm_so != 0 ||
- (size_t)pmatch.rm_eo != l->len))
- continue;
- /* Check for whole word match */
- if (fg_pattern[i].word && pmatch.rm_so != 0) {
- wchar_t wbegin, wend;
-
- wbegin = wend = L' ';
- if (pmatch.rm_so != 0 &&
- sscanf(&l->dat[pmatch.rm_so - 1],
- "%lc", &wbegin) != 1)
- continue;
- if ((size_t)pmatch.rm_eo != l->len &&
- sscanf(&l->dat[pmatch.rm_eo],
- "%lc", &wend) != 1)
- continue;
- if (iswword(wbegin) || iswword(wend))
- continue;
- }
- c = 1;
- if (m < MAX_LINE_MATCHES)
- matches[m++] = pmatch;
- /* matches - skip further patterns */
- if ((color != NULL && !oflag) || qflag || lflag)
- break;
- }
-
- if (vflag) {
- c = !c;
- break;
- }
- /* One pass if we are not recording matches */
- if ((color != NULL && !oflag) || qflag || lflag)
- break;
-
- if (st == (size_t)pmatch.rm_so)
- break; /* No matches */
- }
-
- if (c && binbehave == BINFILE_BIN && nottext)
- return (c); /* Binary file */
-
- /* Dealing with the context */
- if ((tail || c) && !cflag && !qflag && !lflag && !Lflag) {
- if (c) {
- if ((Aflag || Bflag) && !first_global &&
- (first || since_printed > Bflag))
- printf("--\n");
- tail = Aflag;
- if (Bflag > 0)
- printqueue();
- printline(l, ':', matches, m);
- } else {
- printline(l, '-', matches, m);
- tail--;
- }
- first = false;
- first_global = false;
- since_printed = 0;
- } else {
- if (Bflag)
- enqueue(l);
- since_printed++;
- }
- return (c);
-}
-
-/*
- * Safe malloc() for internal use.
- */
-void *
-grep_malloc(size_t size)
-{
- void *ptr;
-
- if ((ptr = malloc(size)) == NULL)
- err(2, "malloc");
- return (ptr);
-}
-
-/*
- * Safe calloc() for internal use.
- */
-void *
-grep_calloc(size_t nmemb, size_t size)
-{
- void *ptr;
-
- if ((ptr = calloc(nmemb, size)) == NULL)
- err(2, "calloc");
- return (ptr);
-}
-
-/*
- * Safe realloc() for internal use.
- */
-void *
-grep_realloc(void *ptr, size_t size)
-{
-
- if ((ptr = realloc(ptr, size)) == NULL)
- err(2, "realloc");
- return (ptr);
-}
-
-/*
- * Safe strdup() for internal use.
- */
-char *
-grep_strdup(const char *str)
-{
- char *ret;
-
- if ((ret = strdup(str)) == NULL)
- err(2, "strdup");
- return (ret);
-}
-
-/*
- * Prints a matching line according to the command line options.
- */
-void
-printline(struct str *line, int sep, regmatch_t *matches, int m)
-{
- size_t a = 0;
- int i, n = 0;
-
- if (!hflag) {
- if (nullflag == 0)
- fputs(line->file, stdout);
- else {
- printf("%s", line->file);
- putchar(0);
- }
- ++n;
- }
- if (nflag) {
- if (n > 0)
- putchar(sep);
- printf("%d", line->line_no);
- ++n;
- }
- if (bflag) {
- if (n > 0)
- putchar(sep);
- printf("%lld", (long long)line->off);
- ++n;
- }
- if (n)
- putchar(sep);
- /* --color and -o */
- if ((oflag || color) && m > 0) {
- for (i = 0; i < m; i++) {
- if (!oflag)
- fwrite(line->dat + a, matches[i].rm_so - a, 1,
- stdout);
- if (color)
- fprintf(stdout, "\33[%sm\33[K", color);
-
- fwrite(line->dat + matches[i].rm_so,
- matches[i].rm_eo - matches[i].rm_so, 1,
- stdout);
- if (color)
- fprintf(stdout, "\33[m\33[K");
- a = matches[i].rm_eo;
- if (oflag)
- putchar('\n');
- }
- if (!oflag) {
- if (line->len - a > 0)
- fwrite(line->dat + a, line->len - a, 1, stdout);
- putchar(line_sep);
- }
- } else {
- fwrite(line->dat, line->len, 1, stdout);
- putchar(line_sep);
- }
-}