Merge "Remove vendor Wifi and BT entries from fs_config.cpp"
diff --git a/adb/Android.bp b/adb/Android.bp
index d81bb4b..46bc02b 100644
--- a/adb/Android.bp
+++ b/adb/Android.bp
@@ -191,6 +191,35 @@
},
}
+cc_benchmark {
+ name: "adb_benchmark",
+ defaults: ["adb_defaults"],
+
+ srcs: ["transport_benchmark.cpp"],
+ target: {
+ android: {
+ static_libs: [
+ "libadbd",
+ ],
+ },
+ host: {
+ static_libs: [
+ "libadb_host",
+ ],
+ },
+ },
+
+ static_libs: [
+ "libbase",
+ "libcutils",
+ "libcrypto_utils",
+ "libcrypto",
+ "libdiagnose_usb",
+ "liblog",
+ "libusb",
+ ],
+}
+
cc_binary_host {
name: "adb",
tags: ["debug"],
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/fdevent.cpp b/adb/fdevent.cpp
index 9776c1b..cf441cf 100644
--- a/adb/fdevent.cpp
+++ b/adb/fdevent.cpp
@@ -75,6 +75,7 @@
static bool main_thread_valid;
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()>>();
@@ -317,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() {
@@ -378,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/socket_test.cpp b/adb/socket_test.cpp
index 6b40056..6c4a8b2 100644
--- a/adb/socket_test.cpp
+++ b/adb/socket_test.cpp
@@ -42,8 +42,6 @@
class LocalSocketTest : public FdeventTest {};
-constexpr auto SLEEP_FOR_FDEVENT = 100ms;
-
TEST_F(LocalSocketTest, smoke) {
// Join two socketpairs with a chain of intermediate socketpairs.
int first[2];
@@ -84,7 +82,6 @@
connect(prev_tail, end);
PrepareThread();
- std::thread thread(fdevent_loop);
for (size_t i = 0; i < MESSAGE_LOOP_COUNT; ++i) {
std::string read_buffer = MESSAGE;
@@ -98,9 +95,9 @@
ASSERT_EQ(0, adb_close(last[1]));
// Wait until the local sockets are closed.
- std::this_thread::sleep_for(SLEEP_FOR_FDEVENT);
+ WaitForFdeventLoop();
ASSERT_EQ(GetAdditionalLocalSocketCount(), fdevent_installed_count());
- TerminateThread(thread);
+ TerminateThread();
}
struct CloseWithPacketArg {
@@ -109,24 +106,39 @@
int cause_close_fd;
};
-static void CloseWithPacketThreadFunc(CloseWithPacketArg* arg) {
- asocket* s = create_local_socket(arg->socket_fd);
- ASSERT_TRUE(s != nullptr);
- arg->bytes_written = 0;
+static void CreateCloser(CloseWithPacketArg* arg) {
+ fdevent_run_on_main_thread([arg]() {
+ asocket* s = create_local_socket(arg->socket_fd);
+ ASSERT_TRUE(s != nullptr);
+ arg->bytes_written = 0;
- std::string data;
- data.resize(MAX_PAYLOAD);
- arg->bytes_written += data.size();
- int ret = s->enqueue(s, std::move(data));
- ASSERT_EQ(1, ret);
+ // On platforms that implement sockets via underlying sockets (e.g. Wine),
+ // a socket can appear to be full, and then become available for writes
+ // again without read being called on the other end. Loop and sleep after
+ // each write to give the underlying implementation time to flush.
+ bool socket_filled = false;
+ for (int i = 0; i < 128; ++i) {
+ std::string data;
+ data.resize(MAX_PAYLOAD);
+ arg->bytes_written += data.size();
+ int ret = s->enqueue(s, std::move(data));
+ if (ret == 1) {
+ socket_filled = true;
+ break;
+ }
+ ASSERT_NE(-1, ret);
- asocket* cause_close_s = create_local_socket(arg->cause_close_fd);
- ASSERT_TRUE(cause_close_s != nullptr);
- cause_close_s->peer = s;
- s->peer = cause_close_s;
- cause_close_s->ready(cause_close_s);
+ std::this_thread::sleep_for(250ms);
+ }
+ ASSERT_TRUE(socket_filled);
- fdevent_loop();
+ asocket* cause_close_s = create_local_socket(arg->cause_close_fd);
+ ASSERT_TRUE(cause_close_s != nullptr);
+ cause_close_s->peer = s;
+ s->peer = cause_close_s;
+ cause_close_s->ready(cause_close_s);
+ });
+ WaitForFdeventLoop();
}
// This test checks if we can close local socket in the following situation:
@@ -143,16 +155,17 @@
arg.cause_close_fd = cause_close_fd[1];
PrepareThread();
- std::thread thread(CloseWithPacketThreadFunc, &arg);
- // Wait until the fdevent_loop() starts.
- std::this_thread::sleep_for(SLEEP_FOR_FDEVENT);
+ CreateCloser(&arg);
+
ASSERT_EQ(0, adb_close(cause_close_fd[0]));
- std::this_thread::sleep_for(SLEEP_FOR_FDEVENT);
+
+ WaitForFdeventLoop();
EXPECT_EQ(1u + GetAdditionalLocalSocketCount(), fdevent_installed_count());
ASSERT_EQ(0, adb_close(socket_fd[0]));
- std::this_thread::sleep_for(SLEEP_FOR_FDEVENT);
+
+ WaitForFdeventLoop();
ASSERT_EQ(GetAdditionalLocalSocketCount(), fdevent_installed_count());
- TerminateThread(thread);
+ TerminateThread();
}
// This test checks if we can read packets from a closing local socket.
@@ -166,11 +179,12 @@
arg.cause_close_fd = cause_close_fd[1];
PrepareThread();
- std::thread thread(CloseWithPacketThreadFunc, &arg);
- // Wait until the fdevent_loop() starts.
- std::this_thread::sleep_for(SLEEP_FOR_FDEVENT);
+ CreateCloser(&arg);
+
+ WaitForFdeventLoop();
ASSERT_EQ(0, adb_close(cause_close_fd[0]));
- std::this_thread::sleep_for(SLEEP_FOR_FDEVENT);
+
+ WaitForFdeventLoop();
EXPECT_EQ(1u + GetAdditionalLocalSocketCount(), fdevent_installed_count());
// Verify if we can read successfully.
@@ -179,9 +193,9 @@
ASSERT_EQ(true, ReadFdExactly(socket_fd[0], buf.data(), buf.size()));
ASSERT_EQ(0, adb_close(socket_fd[0]));
- std::this_thread::sleep_for(SLEEP_FOR_FDEVENT);
+ WaitForFdeventLoop();
ASSERT_EQ(GetAdditionalLocalSocketCount(), fdevent_installed_count());
- TerminateThread(thread);
+ TerminateThread();
}
// This test checks if we can close local socket in the following situation:
@@ -198,15 +212,15 @@
arg.cause_close_fd = cause_close_fd[1];
PrepareThread();
- std::thread thread(CloseWithPacketThreadFunc, &arg);
- // Wait until the fdevent_loop() starts.
- std::this_thread::sleep_for(SLEEP_FOR_FDEVENT);
+ CreateCloser(&arg);
+
+ WaitForFdeventLoop();
EXPECT_EQ(2u + GetAdditionalLocalSocketCount(), fdevent_installed_count());
ASSERT_EQ(0, adb_close(socket_fd[0]));
- std::this_thread::sleep_for(SLEEP_FOR_FDEVENT);
+ WaitForFdeventLoop();
ASSERT_EQ(GetAdditionalLocalSocketCount(), fdevent_installed_count());
- TerminateThread(thread);
+ TerminateThread();
}
// Ensure that if we fail to write output to an fd, we will still flush data coming from it.
@@ -226,7 +240,6 @@
tail->ready(tail);
PrepareThread();
- std::thread thread(fdevent_loop);
EXPECT_TRUE(WriteFdExactly(head_fd[0], "foo", 3));
@@ -242,10 +255,9 @@
adb_close(head_fd[0]);
adb_close(tail_fd[0]);
- // Wait until the local sockets are closed.
- std::this_thread::sleep_for(SLEEP_FOR_FDEVENT);
+ WaitForFdeventLoop();
ASSERT_EQ(GetAdditionalLocalSocketCount(), fdevent_installed_count());
- TerminateThread(thread);
+ TerminateThread();
}
#if defined(__linux__)
@@ -254,21 +266,10 @@
std::string error;
int fd = network_loopback_client(5038, SOCK_STREAM, &error);
ASSERT_GE(fd, 0) << error;
- std::this_thread::sleep_for(200ms);
+ std::this_thread::sleep_for(1s);
ASSERT_EQ(0, adb_close(fd));
}
-struct CloseRdHupSocketArg {
- int socket_fd;
-};
-
-static void CloseRdHupSocketThreadFunc(CloseRdHupSocketArg* arg) {
- asocket* s = create_local_socket(arg->socket_fd);
- ASSERT_TRUE(s != nullptr);
-
- fdevent_loop();
-}
-
// This test checks if we can close sockets in CLOSE_WAIT state.
TEST_F(LocalSocketTest, close_socket_in_CLOSE_WAIT_state) {
std::string error;
@@ -279,22 +280,23 @@
int accept_fd = adb_socket_accept(listen_fd, nullptr, nullptr);
ASSERT_GE(accept_fd, 0);
- CloseRdHupSocketArg arg;
- arg.socket_fd = accept_fd;
PrepareThread();
- std::thread thread(CloseRdHupSocketThreadFunc, &arg);
- // Wait until the fdevent_loop() starts.
- std::this_thread::sleep_for(SLEEP_FOR_FDEVENT);
+ fdevent_run_on_main_thread([accept_fd]() {
+ asocket* s = create_local_socket(accept_fd);
+ ASSERT_TRUE(s != nullptr);
+ });
+
+ WaitForFdeventLoop();
EXPECT_EQ(1u + GetAdditionalLocalSocketCount(), fdevent_installed_count());
// Wait until the client closes its socket.
client_thread.join();
- std::this_thread::sleep_for(SLEEP_FOR_FDEVENT);
+ WaitForFdeventLoop();
ASSERT_EQ(GetAdditionalLocalSocketCount(), fdevent_installed_count());
- TerminateThread(thread);
+ TerminateThread();
}
#endif // defined(__linux__)
diff --git a/adb/sockets.cpp b/adb/sockets.cpp
index e05a3db..0887e6f 100644
--- a/adb/sockets.cpp
+++ b/adb/sockets.cpp
@@ -126,12 +126,12 @@
} else if (rc == -1 && errno == EAGAIN) {
fdevent_add(&s->fde, FDE_WRITE);
return SocketFlushResult::TryAgain;
+ } else {
+ // We failed to write, but it's possible that we can still read from the socket.
+ // Give that a try before giving up.
+ s->has_write_error = true;
+ break;
}
-
- // We failed to write, but it's possible that we can still read from the socket.
- // Give that a try before giving up.
- s->has_write_error = true;
- break;
}
// If we sent the last packet of a closing socket, we can now destroy it.
diff --git a/adb/sysdeps_test.cpp b/adb/sysdeps_test.cpp
index fd19882..79cebe6 100644
--- a/adb/sysdeps_test.cpp
+++ b/adb/sysdeps_test.cpp
@@ -121,10 +121,13 @@
adb_pollfd pfd[3] = {};
pfd[0].fd = fds[0];
pfd[0].events = POLLRDNORM;
+ pfd[0].revents = ~0;
pfd[1].fd = INT_MAX;
pfd[1].events = POLLRDNORM;
+ pfd[1].revents = ~0;
pfd[2].fd = fds[1];
pfd[2].events = POLLWRNORM;
+ pfd[2].revents = ~0;
ASSERT_TRUE(WriteFdExactly(fds[1], "foo", 4));
@@ -136,6 +139,17 @@
EXPECT_EQ(POLLRDNORM, pfd[0].revents);
EXPECT_EQ(POLLNVAL, pfd[1].revents);
EXPECT_EQ(POLLWRNORM, pfd[2].revents);
+
+ // Make sure that we return immediately if an invalid FD is given.
+ pfd[0].fd = fds[0];
+ pfd[0].events = POLLRDNORM;
+ pfd[0].revents = ~0;
+ pfd[1].fd = INT_MAX;
+ pfd[1].events = POLLRDNORM;
+ pfd[1].revents = ~0;
+ EXPECT_EQ(2, adb_poll(pfd, 2, -1));
+ EXPECT_EQ(POLLRDNORM, pfd[0].revents);
+ EXPECT_EQ(POLLNVAL, pfd[1].revents);
}
TEST_F(sysdeps_poll, duplicate_fd) {
diff --git a/adb/sysdeps_win32.cpp b/adb/sysdeps_win32.cpp
index 62f4ac8..7d35fb6 100644
--- a/adb/sysdeps_win32.cpp
+++ b/adb/sysdeps_win32.cpp
@@ -529,6 +529,7 @@
int skipped = 0;
std::vector<WSAPOLLFD> sockets;
std::vector<adb_pollfd*> original;
+
for (size_t i = 0; i < nfds; ++i) {
FH fh = _fh_from_int(fds[i].fd, __func__);
if (!fh || !fh->used || fh->clazz != &_fh_socket_class) {
@@ -549,6 +550,11 @@
return skipped;
}
+ // If we have any invalid FDs in our FD set, make sure to return immediately.
+ if (skipped > 0) {
+ timeout = 0;
+ }
+
int result = WSAPoll(sockets.data(), sockets.size(), timeout);
if (result == SOCKET_ERROR) {
_socket_set_errno(WSAGetLastError());
@@ -560,7 +566,7 @@
original[i]->revents = sockets[i].revents;
}
- // WSAPoll appears to return the number of unique FDs with avaiable events, instead of how many
+ // WSAPoll appears to return the number of unique FDs with available events, instead of how many
// of the pollfd elements have a non-zero revents field, which is what it and poll are specified
// to do. Ignore its result and calculate the proper return value.
result = 0;
diff --git a/adb/test_adb.py b/adb/test_adb.py
index e771106..3bb433d 100644
--- a/adb/test_adb.py
+++ b/adb/test_adb.py
@@ -162,15 +162,14 @@
Bug: https://code.google.com/p/android/issues/detail?id=21021
"""
- port = 12345
-
with contextlib.closing(
socket.socket(socket.AF_INET, socket.SOCK_STREAM)) as listener:
# Use SO_REUSEADDR so subsequent runs of the test can grab the port
# even if it is in TIME_WAIT.
listener.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
- listener.bind(('127.0.0.1', port))
+ listener.bind(('127.0.0.1', 0))
listener.listen(4)
+ port = listener.getsockname()[1]
# Now that listening has started, start adb emu kill, telling it to
# connect to our mock emulator.
@@ -233,6 +232,24 @@
output.strip(), 'connected to localhost:{}'.format(port))
s.close()
+ def test_already_connected(self):
+ s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+ s.bind(('127.0.0.1', 0))
+ s.listen(2)
+
+ port = s.getsockname()[1]
+ output = subprocess.check_output(
+ ['adb', 'connect', 'localhost:{}'.format(port)])
+
+ self.assertEqual(
+ output.strip(), 'connected to localhost:{}'.format(port))
+
+ # b/31250450: this always returns 0 but probably shouldn't.
+ output = subprocess.check_output(
+ ['adb', 'connect', 'localhost:{}'.format(port)])
+
+ self.assertEqual(
+ output.strip(), 'already connected to localhost:{}'.format(port))
def main():
random.seed(0)
diff --git a/adb/transport.cpp b/adb/transport.cpp
index 37b56e2..2867d38 100644
--- a/adb/transport.cpp
+++ b/adb/transport.cpp
@@ -77,7 +77,15 @@
Stop();
}
+static void AssumeLocked(std::mutex& mutex) ASSERT_CAPABILITY(mutex) {}
+
void BlockingConnectionAdapter::Start() {
+ std::lock_guard<std::mutex> lock(mutex_);
+ if (started_) {
+ LOG(FATAL) << "BlockingConnectionAdapter(" << this->transport_name_
+ << "): started multiple times";
+ }
+
read_thread_ = std::thread([this]() {
LOG(INFO) << this->transport_name_ << ": read thread spawning";
while (true) {
@@ -95,7 +103,11 @@
LOG(INFO) << this->transport_name_ << ": write thread spawning";
while (true) {
std::unique_lock<std::mutex> lock(mutex_);
- cv_.wait(lock, [this]() { return this->stopped_ || !this->write_queue_.empty(); });
+ cv_.wait(lock, [this]() REQUIRES(mutex_) {
+ return this->stopped_ || !this->write_queue_.empty();
+ });
+
+ AssumeLocked(mutex_);
if (this->stopped_) {
return;
@@ -111,25 +123,44 @@
}
std::call_once(this->error_flag_, [this]() { this->error_callback_(this, "write failed"); });
});
+
+ started_ = true;
}
void BlockingConnectionAdapter::Stop() {
- std::unique_lock<std::mutex> lock(mutex_);
- if (stopped_) {
- LOG(INFO) << "BlockingConnectionAdapter(" << this->transport_name_ << "): already stopped";
- return;
- }
+ {
+ std::lock_guard<std::mutex> lock(mutex_);
+ if (!started_) {
+ LOG(INFO) << "BlockingConnectionAdapter(" << this->transport_name_ << "): not started";
+ return;
+ }
- stopped_ = true;
- lock.unlock();
+ 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();
- read_thread_.join();
- write_thread_.join();
+
+ // 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"); });
@@ -137,7 +168,7 @@
bool BlockingConnectionAdapter::Write(std::unique_ptr<apacket> packet) {
{
- std::unique_lock<std::mutex> lock(this->mutex_);
+ std::lock_guard<std::mutex> lock(this->mutex_);
write_queue_.emplace_back(std::move(packet));
}
diff --git a/adb/transport.h b/adb/transport.h
index 8b71e34..d18c362 100644
--- a/adb/transport.h
+++ b/adb/transport.h
@@ -30,6 +30,7 @@
#include <thread>
#include <unordered_set>
+#include <android-base/thread_annotations.h>
#include <openssl/rsa.h>
#include "adb.h"
@@ -121,13 +122,14 @@
virtual void Start() override final;
virtual void Stop() override final;
- bool stopped_ = false;
+ bool started_ GUARDED_BY(mutex_) = false;
+ bool stopped_ GUARDED_BY(mutex_) = false;
std::unique_ptr<BlockingConnection> underlying_;
- std::thread read_thread_;
- std::thread write_thread_;
+ std::thread read_thread_ GUARDED_BY(mutex_);
+ std::thread write_thread_ GUARDED_BY(mutex_);
- std::deque<std::unique_ptr<apacket>> write_queue_;
+ std::deque<std::unique_ptr<apacket>> write_queue_ GUARDED_BY(mutex_);
std::mutex mutex_;
std::condition_variable cv_;
diff --git a/adb/transport_benchmark.cpp b/adb/transport_benchmark.cpp
new file mode 100644
index 0000000..ffe4cbc
--- /dev/null
+++ b/adb/transport_benchmark.cpp
@@ -0,0 +1,179 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdio.h>
+
+#include <android-base/logging.h>
+#include <benchmark/benchmark.h>
+
+#include "adb_trace.h"
+#include "sysdeps.h"
+#include "transport.h"
+
+#define ADB_CONNECTION_BENCHMARK(benchmark_name, ...) \
+ BENCHMARK_TEMPLATE(benchmark_name, FdConnection, ##__VA_ARGS__) \
+ ->Arg(1) \
+ ->Arg(16384) \
+ ->Arg(MAX_PAYLOAD) \
+ ->UseRealTime()
+
+template <typename ConnectionType>
+std::unique_ptr<Connection> MakeConnection(unique_fd fd);
+
+template <>
+std::unique_ptr<Connection> MakeConnection<FdConnection>(unique_fd fd) {
+ auto fd_connection = std::make_unique<FdConnection>(std::move(fd));
+ return std::make_unique<BlockingConnectionAdapter>(std::move(fd_connection));
+}
+
+template <typename ConnectionType>
+void BM_Connection_Unidirectional(benchmark::State& state) {
+ int fds[2];
+ if (adb_socketpair(fds) != 0) {
+ LOG(FATAL) << "failed to create socketpair";
+ }
+
+ auto client = MakeConnection<ConnectionType>(unique_fd(fds[0]));
+ auto server = MakeConnection<ConnectionType>(unique_fd(fds[1]));
+
+ std::atomic<size_t> received_bytes;
+
+ client->SetReadCallback([](Connection*, std::unique_ptr<apacket>) -> bool { return true; });
+ server->SetReadCallback([&received_bytes](Connection*, std::unique_ptr<apacket> packet) -> bool {
+ received_bytes += packet->payload.size();
+ return true;
+ });
+
+ client->SetErrorCallback(
+ [](Connection*, const std::string& error) { LOG(INFO) << "client closed: " << error; });
+ server->SetErrorCallback(
+ [](Connection*, const std::string& error) { LOG(INFO) << "server closed: " << error; });
+
+ client->Start();
+ server->Start();
+
+ for (auto _ : state) {
+ size_t data_size = state.range(0);
+ std::unique_ptr<apacket> packet = std::make_unique<apacket>();
+ memset(&packet->msg, 0, sizeof(packet->msg));
+ packet->msg.command = A_WRTE;
+ packet->msg.data_length = data_size;
+ packet->payload.resize(data_size);
+
+ memset(&packet->payload[0], 0xff, data_size);
+
+ received_bytes = 0;
+ client->Write(std::move(packet));
+ while (received_bytes < data_size) {
+ continue;
+ }
+ }
+ state.SetBytesProcessed(static_cast<int64_t>(state.iterations()) * state.range(0));
+
+ client->Stop();
+ server->Stop();
+}
+
+ADB_CONNECTION_BENCHMARK(BM_Connection_Unidirectional);
+
+enum class ThreadPolicy {
+ MainThread,
+ SameThread,
+};
+
+template <typename ConnectionType, enum ThreadPolicy Policy>
+void BM_Connection_Echo(benchmark::State& state) {
+ int fds[2];
+ if (adb_socketpair(fds) != 0) {
+ LOG(FATAL) << "failed to create socketpair";
+ }
+
+ auto client = MakeConnection<ConnectionType>(unique_fd(fds[0]));
+ auto server = MakeConnection<ConnectionType>(unique_fd(fds[1]));
+
+ std::atomic<size_t> received_bytes;
+
+ fdevent_reset();
+ std::thread fdevent_thread([]() { fdevent_loop(); });
+
+ client->SetReadCallback([&received_bytes](Connection*, std::unique_ptr<apacket> packet) -> bool {
+ received_bytes += packet->payload.size();
+ return true;
+ });
+
+ static const auto handle_packet = [](Connection* connection, std::unique_ptr<apacket> packet) {
+ connection->Write(std::move(packet));
+ };
+
+ server->SetReadCallback([](Connection* connection, std::unique_ptr<apacket> packet) -> bool {
+ if (Policy == ThreadPolicy::MainThread) {
+ auto raw_packet = packet.release();
+ fdevent_run_on_main_thread([connection, raw_packet]() {
+ std::unique_ptr<apacket> packet(raw_packet);
+ handle_packet(connection, std::move(packet));
+ });
+ } else {
+ handle_packet(connection, std::move(packet));
+ }
+ return true;
+ });
+
+ client->SetErrorCallback(
+ [](Connection*, const std::string& error) { LOG(INFO) << "client closed: " << error; });
+ server->SetErrorCallback(
+ [](Connection*, const std::string& error) { LOG(INFO) << "server closed: " << error; });
+
+ client->Start();
+ server->Start();
+
+ for (auto _ : state) {
+ size_t data_size = state.range(0);
+ std::unique_ptr<apacket> packet = std::make_unique<apacket>();
+ memset(&packet->msg, 0, sizeof(packet->msg));
+ packet->msg.command = A_WRTE;
+ packet->msg.data_length = data_size;
+ packet->payload.resize(data_size);
+
+ memset(&packet->payload[0], 0xff, data_size);
+
+ received_bytes = 0;
+ client->Write(std::move(packet));
+ while (received_bytes < data_size) {
+ continue;
+ }
+ }
+ state.SetBytesProcessed(static_cast<int64_t>(state.iterations()) * state.range(0));
+
+ client->Stop();
+ server->Stop();
+
+ // TODO: Make it so that you don't need to poke the fdevent loop to make it terminate?
+ fdevent_terminate_loop();
+ fdevent_run_on_main_thread([]() {});
+
+ fdevent_thread.join();
+}
+
+ADB_CONNECTION_BENCHMARK(BM_Connection_Echo, ThreadPolicy::SameThread);
+ADB_CONNECTION_BENCHMARK(BM_Connection_Echo, ThreadPolicy::MainThread);
+
+int main(int argc, char** argv) {
+ android::base::SetMinimumLogSeverity(android::base::WARNING);
+ adb_trace_init(argv);
+ ::benchmark::Initialize(&argc, argv);
+ if (::benchmark::ReportUnrecognizedArguments(argc, argv)) return 1;
+ ::benchmark::RunSpecifiedBenchmarks();
+}
diff --git a/fastboot/Android.mk b/fastboot/Android.mk
index f5bcc26..944b00b 100644
--- a/fastboot/Android.mk
+++ b/fastboot/Android.mk
@@ -22,7 +22,8 @@
LOCAL_C_INCLUDES := \
$(LOCAL_PATH)/../adb \
- $(LOCAL_PATH)/../mkbootimg \
+
+LOCAL_HEADER_LIBRARIES := bootimg_headers
LOCAL_SRC_FILES := \
bootimg_utils.cpp \
diff --git a/fastboot/bootimg_utils.cpp b/fastboot/bootimg_utils.cpp
index 62a26b3..23443ec 100644
--- a/fastboot/bootimg_utils.cpp
+++ b/fastboot/bootimg_utils.cpp
@@ -34,26 +34,25 @@
#include <stdlib.h>
#include <string.h>
-void bootimg_set_cmdline(boot_img_hdr* h, const char* cmdline) {
+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);
}
-boot_img_hdr* 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,
- int64_t* bootimg_size)
-{
+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;
+ int64_t header_actual = sizeof(boot_img_hdr_v1) & (~page_mask);
int64_t kernel_actual = (kernel_size + page_mask) & (~page_mask);
int64_t ramdisk_actual = (ramdisk_size + page_mask) & (~page_mask);
int64_t second_actual = (second_size + page_mask) & (~page_mask);
- *bootimg_size = page_size + kernel_actual + ramdisk_actual + second_actual;
+ *bootimg_size = header_actual + kernel_actual + ramdisk_actual + second_actual;
- boot_img_hdr* hdr = reinterpret_cast<boot_img_hdr*>(calloc(*bootimg_size, 1));
+ boot_img_hdr_v1* hdr = reinterpret_cast<boot_img_hdr_v1*>(calloc(*bootimg_size, 1));
if (hdr == nullptr) {
return hdr;
}
@@ -71,9 +70,13 @@
hdr->page_size = page_size;
+ if (header_version) {
+ hdr->header_version = header_version;
+ 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);
-
return hdr;
}
diff --git a/fastboot/bootimg_utils.h b/fastboot/bootimg_utils.h
index fcc8662..d3993f5 100644
--- a/fastboot/bootimg_utils.h
+++ b/fastboot/bootimg_utils.h
@@ -33,11 +33,10 @@
#include <inttypes.h>
#include <sys/types.h>
-void bootimg_set_cmdline(boot_img_hdr* h, const char* cmdline);
-boot_img_hdr* 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,
- int64_t* bootimg_size);
+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);
#endif
diff --git a/fastboot/engine.cpp b/fastboot/engine.cpp
index 60b7124..551ddba 100644
--- a/fastboot/engine.cpp
+++ b/fastboot/engine.cpp
@@ -109,32 +109,32 @@
void fb_set_active(const std::string& slot) {
Action& a = queue_action(OP_COMMAND, "set_active:" + slot);
- a.msg = "Setting current slot to '" + slot + "'...";
+ a.msg = "Setting current slot to '" + slot + "'";
}
void fb_queue_erase(const std::string& partition) {
Action& a = queue_action(OP_COMMAND, "erase:" + partition);
- a.msg = "Erasing '" + partition + "'...";
+ a.msg = "Erasing '" + partition + "'";
}
void fb_queue_flash_fd(const std::string& partition, int fd, uint32_t sz) {
Action& a = queue_action(OP_DOWNLOAD_FD, "");
a.fd = fd;
a.size = sz;
- a.msg = android::base::StringPrintf("Sending '%s' (%d KB)...", partition.c_str(), sz / 1024);
+ a.msg = android::base::StringPrintf("Sending '%s' (%u KB)", partition.c_str(), sz / 1024);
Action& b = queue_action(OP_COMMAND, "flash:" + partition);
- b.msg = "Writing '" + partition + "'...";
+ b.msg = "Writing '" + partition + "'";
}
void fb_queue_flash(const std::string& partition, void* data, uint32_t sz) {
Action& a = queue_action(OP_DOWNLOAD, "");
a.data = data;
a.size = sz;
- a.msg = android::base::StringPrintf("Sending '%s' (%d KB)...", partition.c_str(), sz / 1024);
+ a.msg = android::base::StringPrintf("Sending '%s' (%u KB)", partition.c_str(), sz / 1024);
Action& b = queue_action(OP_COMMAND, "flash:" + partition);
- b.msg = "Writing '" + partition + "'...";
+ b.msg = "Writing '" + partition + "'";
}
void fb_queue_flash_sparse(const std::string& partition, struct sparse_file* s, uint32_t sz,
@@ -142,12 +142,12 @@
Action& a = queue_action(OP_DOWNLOAD_SPARSE, "");
a.data = s;
a.size = 0;
- a.msg = android::base::StringPrintf("Sending sparse '%s' %zu/%zu (%d KB)...", partition.c_str(),
+ a.msg = android::base::StringPrintf("Sending sparse '%s' %zu/%zu (%u KB)", partition.c_str(),
current, total, sz / 1024);
Action& b = queue_action(OP_COMMAND, "flash:" + partition);
- b.msg =
- android::base::StringPrintf("Writing '%s' %zu/%zu...", partition.c_str(), current, total);
+ b.msg = android::base::StringPrintf("Writing sparse '%s' %zu/%zu", partition.c_str(), current,
+ total);
}
static int match(const char* str, const char** value, unsigned count) {
@@ -270,7 +270,7 @@
void fb_queue_reboot() {
Action& a = queue_action(OP_COMMAND, "reboot");
a.func = cb_do_nothing;
- a.msg = "Rebooting...";
+ a.msg = "Rebooting";
}
void fb_queue_command(const std::string& cmd, const std::string& msg) {
@@ -289,7 +289,7 @@
Action& a = queue_action(OP_DOWNLOAD_FD, "");
a.fd = fd;
a.size = sz;
- a.msg = android::base::StringPrintf("Sending '%s' (%d KB)", name.c_str(), sz / 1024);
+ a.msg = android::base::StringPrintf("Sending '%s' (%u KB)", name.c_str(), sz / 1024);
}
void fb_queue_upload(const std::string& outfile) {
@@ -312,7 +312,8 @@
for (auto& a : action_list) {
a->start = now();
if (!a->msg.empty()) {
- fprintf(stderr, "%s\n", a->msg.c_str());
+ fprintf(stderr, "%-50s ", a->msg.c_str());
+ verbose("\n");
}
if (a->op == OP_DOWNLOAD) {
status = fb_download_data(transport, a->data, a->size);
@@ -333,6 +334,7 @@
if (status) break;
} else if (a->op == OP_NOTICE) {
// We already showed the notice because it's in `Action::msg`.
+ fprintf(stderr, "\n");
} else if (a->op == OP_DOWNLOAD_SPARSE) {
status = fb_download_data_sparse(transport, reinterpret_cast<sparse_file*>(a->data));
status = a->func(*a, status, status ? fb_get_error().c_str() : "");
diff --git a/fastboot/fastboot.bash b/fastboot/fastboot.bash
new file mode 100644
index 0000000..dca3b4e
--- /dev/null
+++ b/fastboot/fastboot.bash
@@ -0,0 +1,182 @@
+# /* vim: set ai ts=4 ft=sh: */
+#
+# Copyright 2017, The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+_fastboot() {
+ if ! type -t "$1" >/dev/null; then
+ return
+ fi
+
+ if type -t _init_completion >/dev/null; then
+ _init_completion || return
+ fi
+
+ local where i cur serial
+ COMPREPLY=()
+
+ serial="${ANDROID_SERIAL:-none}"
+ where=OPTIONS
+ for ((i=1; i <= COMP_CWORD; i++)); do
+ cur="${COMP_WORDS[i]}"
+ case "${cur}" in
+ -s)
+ where=OPT_SERIAL
+ ;;
+ --slot)
+ where=OPT_SLOT
+ ;;
+ -*)
+ where=OPTIONS
+ ;;
+ *)
+ if [[ $where == OPT_SERIAL ]]; then
+ where=OPT_SERIAL_ARG
+ serial=${cur}
+ elif [[ $where == OPT_SLOT ]]; then
+ where=OPT_SLOT_ARG
+ else
+ where=COMMAND
+ break
+ fi
+ ;;
+ esac
+ done
+
+ if [[ $where == COMMAND && $i -ge $COMP_CWORD ]]; then
+ where=OPTIONS
+ fi
+
+ OPTIONS="-a -c --disable-verification --disable-verity -h --help -s --set-active --skip-secondary --skip-reboot --slot -u --version -w"
+ COMMAND="continue devices erase flash flashall flashing format getvar get_staged help oem reboot stage update"
+
+ case $where in
+ OPTIONS|OPT_SERIAL)
+ COMPREPLY=( $(compgen -W "$OPTIONS $COMMAND" -- "$cur") )
+ ;;
+ OPT_SERIAL_ARG)
+ local devices=$(command fastboot devices 2> /dev/null | awk '{ print $1 }')
+ COMPREPLY=( $(compgen -W "${devices}" -- ${cur}) )
+ ;;
+ OPT_SLOT_ARG)
+ local slots="a all b other"
+ COMPREPLY=( $(compgen -W "${slots}" -- ${cur}) )
+ ;;
+ COMMAND)
+ if [[ $i -eq $COMP_CWORD ]]; then
+ COMPREPLY=( $(compgen -W "$COMMAND" -- "$cur") )
+ else
+ i=$((i+1))
+ case "${cur}" in
+ flash)
+ _fastboot_cmd_flash "$serial" $i
+ ;;
+ reboot)
+ if [[ $COMP_CWORD == $i ]]; then
+ args="bootloader"
+ COMPREPLY=( $(compgen -W "${args}" -- "${COMP_WORDS[i]}") )
+ fi
+ ;;
+ update)
+ _fastboot_cmd_update "$serial" $i
+ ;;
+ esac
+ fi
+ ;;
+ esac
+
+ return 0
+}
+
+_fastboot_cmd_flash() {
+ local serial i cur
+ local partitions
+
+ serial=$1
+ i=$2
+
+ cur="${COMP_WORDS[COMP_CWORD]}"
+ if [[ $i -eq $COMP_CWORD ]]; then
+ partitions="boot bootloader dtbo modem odm oem product radio recovery system vbmeta vendor"
+ COMPREPLY=( $(compgen -W "$partitions" -- $cur) )
+ else
+ _fastboot_util_complete_local_file "${cur}" '!*.img'
+ fi
+}
+
+_fastboot_cmd_update() {
+ local serial i cur
+
+ serial=$1
+ i=$2
+
+ cur="${COMP_WORDS[COMP_CWORD]}"
+
+ _fastboot_util_complete_local_file "${cur}" '!*.zip'
+}
+
+_fastboot_util_complete_local_file() {
+ local file xspec i j IFS=$'\n'
+ local -a dirs files
+
+ file=$1
+ xspec=$2
+
+ # Since we're probably doing file completion here, don't add a space after.
+ if [[ $(type -t compopt) = "builtin" ]]; then
+ compopt -o plusdirs
+ if [[ "${xspec}" == "" ]]; then
+ COMPREPLY=( ${COMPREPLY[@]:-} $(compgen -f -- "${cur}") )
+ else
+ compopt +o filenames
+ COMPREPLY=( ${COMPREPLY[@]:-} $(compgen -f -X "${xspec}" -- "${cur}") )
+ fi
+ else
+ # Work-around for shells with no compopt
+
+ dirs=( $(compgen -d -- "${cur}" ) )
+
+ if [[ "${xspec}" == "" ]]; then
+ files=( ${COMPREPLY[@]:-} $(compgen -f -- "${cur}") )
+ else
+ files=( ${COMPREPLY[@]:-} $(compgen -f -X "${xspec}" -- "${cur}") )
+ fi
+
+ COMPREPLY=( $(
+ for i in "${files[@]}"; do
+ local skip=
+ for j in "${dirs[@]}"; do
+ if [[ $i == $j ]]; then
+ skip=1
+ break
+ fi
+ done
+ [[ -n $skip ]] || printf "%s\n" "$i"
+ done
+ ))
+
+ COMPREPLY=( ${COMPREPLY[@]:-} $(
+ for i in "${dirs[@]}"; do
+ printf "%s/\n" "$i"
+ done
+ ))
+ fi
+}
+
+if [[ $(type -t compopt) = "builtin" ]]; then
+ complete -F _fastboot fastboot
+else
+ complete -o nospace -F _fastboot fastboot
+fi
diff --git a/fastboot/fastboot.cpp b/fastboot/fastboot.cpp
index 237f081..220a96a 100644
--- a/fastboot/fastboot.cpp
+++ b/fastboot/fastboot.cpp
@@ -238,7 +238,7 @@
// Opens a new Transport connected to a device. If |serial| is non-null it will be used to identify
// a specific device, otherwise the first USB device found will be used.
//
-// If |serial| is non-null but invalid, this prints an error message to stderr and returns nullptr.
+// If |serial| is non-null but invalid, this exits.
// Otherwise it blocks until the target is available.
//
// The returned Transport is a singleton, so multiple calls to this function will return the same
@@ -270,9 +270,7 @@
if (net_address != nullptr) {
std::string error;
if (!android::base::ParseNetAddress(net_address, &host, &port, nullptr, &error)) {
- fprintf(stderr, "error: Invalid network address '%s': %s\n", net_address,
- error.c_str());
- return nullptr;
+ die("invalid network address '%s': %s\n", net_address, error.c_str());
}
}
}
@@ -328,114 +326,79 @@
// clang-format off
fprintf(stdout,
/* 1234567890123456789012345678901234567890123456789012345678901234567890123456 */
- "usage: fastboot [ <option> ] <command>\n"
+ "usage: fastboot [OPTION...] COMMAND...\n"
"\n"
- "commands:\n"
- " update <filename> Reflash device from update.zip.\n"
- " Sets the flashed slot as active.\n"
- " flashall Flash boot, system, vendor, and --\n"
- " if found -- recovery. If the device\n"
- " supports slots, the slot that has\n"
- " been flashed to is set as active.\n"
- " Secondary images may be flashed to\n"
- " an inactive slot.\n"
- " flash <partition> [ <filename> ] Write a file to a flash partition.\n"
- " flashing lock Locks the device. Prevents flashing.\n"
- " flashing unlock Unlocks the device. Allows flashing\n"
- " any partition except\n"
- " bootloader-related partitions.\n"
- " flashing lock_critical Prevents flashing bootloader-related\n"
- " partitions.\n"
- " flashing unlock_critical Enables flashing bootloader-related\n"
- " partitions.\n"
- " flashing get_unlock_ability Queries bootloader to see if the\n"
- " device is unlocked.\n"
- " flashing get_unlock_bootloader_nonce Queries the bootloader to get the\n"
- " unlock nonce.\n"
- " flashing unlock_bootloader <request> Issue unlock bootloader using request.\n"
- " flashing lock_bootloader Locks the bootloader to prevent\n"
- " bootloader version rollback.\n"
- " erase <partition> Erase a flash partition.\n"
- " format[:[<fs type>][:[<size>]] <partition>\n"
- " Format a flash partition. Can\n"
- " override the fs type and/or size\n"
- " the bootloader reports.\n"
- " getvar <variable> Display a bootloader variable.\n"
- " set_active <slot> Sets the active slot. If slots are\n"
- " not supported, this does nothing.\n"
- " boot <kernel> [ <ramdisk> [ <second> ] ] Download and boot kernel.\n"
- " flash:raw <bootable-partition> <kernel> [ <ramdisk> [ <second> ] ]\n"
- " Create bootimage and flash it.\n"
- " devices [-l] List all connected devices [with\n"
- " device paths].\n"
- " continue Continue with autoboot.\n"
- " reboot [bootloader|emergency] Reboot device [into bootloader or emergency mode].\n"
- " reboot-bootloader Reboot device into bootloader.\n"
- " oem <parameter1> ... <parameterN> Executes oem specific command.\n"
- " stage <infile> Sends contents of <infile> to stage for\n"
- " the next command. Supported only on\n"
- " Android Things devices.\n"
- " get_staged <outfile> Receives data to <outfile> staged by the\n"
- " last command. Supported only on Android\n"
- " Things devices.\n"
- " help Show this help message.\n"
+ "flashing:\n"
+ " update ZIP Flash all partitions from an update.zip package.\n"
+ " flashall Flash all partitions from $ANDROID_PRODUCT_OUT.\n"
+ " On A/B devices, flashed slot is set as active.\n"
+ " Secondary images may be flashed to inactive slot.\n"
+ " flash PARTITION [FILENAME]\n"
+ " Flash given partition only.\n"
+ "\n"
+ "basics:\n"
+ " devices [-l] List devices in bootloader (-l: with device paths).\n"
+ " getvar NAME Display given bootloader variable.\n"
+ " reboot [bootloader] Reboot device.\n"
+ "\n"
+ "locking/unlocking:\n"
+ " flashing lock|unlock Lock/unlock partitions for flashing\n"
+ " flashing lock_critical|unlock_critical\n"
+ " Lock/unlock 'critical' bootloader partitions.\n"
+ " flashing get_unlock_ability\n"
+ " Check whether unlocking is allowed (1) or not(0).\n"
+ "\n"
+ "advanced:\n"
+ " erase PARTITION Erase a flash partition.\n"
+ " format[:FS_TYPE[:SIZE]] PARTITION\n"
+ " Format a flash partition.\n"
+ " set_active SLOT Set the active slot.\n"
+ " oem [COMMAND...] Execute OEM-specific command.\n"
+ "\n"
+ "boot image:\n"
+ " boot KERNEL [RAMDISK [SECOND]]\n"
+ " Download and boot kernel from RAM.\n"
+ " flash:raw PARTITION KERNEL [RAMDISK [SECOND]]\n"
+ " Create boot image and flash it.\n"
+ // TODO: give -c a long option, and remove the short options for this group?
+ " -c CMDLINE Override kernel command line.\n"
+ " --base ADDRESS Set kernel base address (default: 0x10000000).\n"
+ " --kernel-offset Set kernel offset (default: 0x00008000).\n"
+ " --ramdisk-offset Set ramdisk offset (default: 0x01000000).\n"
+ " --tags-offset Set tags offset (default: 0x00000100).\n"
+ " --page-size BYTES Set flash page size (default: 2048).\n"
+ " --header-version VERSION Set boot image header version.\n"
+ "\n"
+ // TODO: what device(s) used this? is there any documentation?
+ //" continue Continue with autoboot.\n"
+ //"\n"
+ "Android Things:\n"
+ " stage IN_FILE Sends given file to stage for the next command.\n"
+ " get_staged OUT_FILE Writes data staged by the last command to a file.\n"
"\n"
"options:\n"
- " -w Erase userdata and cache (and format\n"
- " if supported by partition type).\n"
- " -u Do not erase partition before\n"
- " formatting.\n"
- " -s <specific device> Specify a device. For USB, provide either\n"
- " a serial number or path to device port.\n"
- " For ethernet, provide an address in the\n"
- " form <protocol>:<hostname>[:port] where\n"
- " <protocol> is either tcp or udp.\n"
- " -c <cmdline> Override kernel commandline.\n"
- " -i <vendor id> Specify a custom USB vendor id.\n"
- " -b, --base <base_addr> Specify a custom kernel base\n"
- " address (default: 0x10000000).\n"
- " --kernel-offset Specify a custom kernel offset.\n"
- " (default: 0x00008000)\n"
- " --ramdisk-offset Specify a custom ramdisk offset.\n"
- " (default: 0x01000000)\n"
- " --tags-offset Specify a custom tags offset.\n"
- " (default: 0x00000100)\n"
- " -n, --page-size <page size> Specify the nand page size\n"
- " (default: 2048).\n"
- " -S <size>[K|M|G] Automatically sparse files greater\n"
- " than 'size'. 0 to disable.\n"
- " --slot <slot> Specify slot name to be used if the\n"
- " device supports slots. All operations\n"
- " on partitions that support slots will\n"
- " be done on the slot specified.\n"
- " 'all' can be given to refer to all slots.\n"
- " 'other' can be given to refer to a\n"
- " non-current slot. If this flag is not\n"
- " used, slotted partitions will default\n"
- " to the current active slot.\n"
- " -a, --set-active[=<slot>] Sets the active slot. If no slot is\n"
- " provided, this will default to the value\n"
- " given by --slot. If slots are not\n"
- " supported, this does nothing. This will\n"
- " run after all non-reboot commands.\n"
- " --skip-secondary Will not flash secondary slots when\n"
- " performing a flashall or update. This\n"
- " will preserve data on other slots.\n"
- " --skip-reboot Will not reboot the device when\n"
- " performing commands that normally\n"
- " trigger a reboot.\n"
- " --disable-verity Set the disable-verity flag in the\n"
- " the vbmeta image being flashed.\n"
- " --disable-verification Set the disable-verification flag in"
- " the vbmeta image being flashed.\n"
+ " -w Wipe userdata.\n"
+ " -u Do not erase partition first when formatting.\n"
+ " -s SERIAL Specify a USB device.\n"
+ " -s tcp|udp:HOST[:PORT] Specify a network device.\n"
+ // TODO: remove -i?
+ " -i VENDOR_ID Filter devices by USB vendor id.\n"
+ " -S SIZE[K|M|G] Use sparse files above this limit (0 to disable).\n"
+ " --slot SLOT Use SLOT; 'all' for both slots, 'other' for\n"
+ " non-current slot (default: current active slot).\n"
+ " --set-active[=SLOT] Sets the active slot before rebooting.\n"
+ " --skip-secondary Don't flash secondary slots in flashall/update.\n"
+ " --skip-reboot Don't reboot device after flashing.\n"
+ " --disable-verity Sets disable-verity when flashing vbmeta.\n"
+ " --disable-verification Sets disable-verification when flashing vbmeta.\n"
#if !defined(_WIN32)
- " --wipe-and-use-fbe On devices which support it,\n"
- " erase userdata and cache, and\n"
- " enable file-based encryption\n"
+ " --wipe-and-use-fbe Enable file-based encryption, wiping userdata.\n"
#endif
- " --unbuffered Do not buffer input or output.\n"
- " --version Display version.\n"
- " -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;
@@ -443,17 +406,23 @@
static void* load_bootable_image(const std::string& kernel, const std::string& ramdisk,
const std::string& second_stage, int64_t* sz,
- const char* cmdline) {
+ const char* cmdline, uint32_t header_version) {
int64_t ksize;
void* kdata = load_file(kernel.c_str(), &ksize);
if (kdata == nullptr) die("cannot load '%s': %s", kernel.c_str(), strerror(errno));
// Is this actually a boot image?
- if (ksize < static_cast<int64_t>(sizeof(boot_img_hdr))) {
+ if (ksize < static_cast<int64_t>(sizeof(boot_img_hdr_v1))) {
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*>(kdata), cmdline);
+ if (cmdline) bootimg_set_cmdline(reinterpret_cast<boot_img_hdr_v1*>(kdata), cmdline);
+ uint32_t header_version_existing =
+ reinterpret_cast<boot_img_hdr_v1*>(kdata)->header_version;
+ if (header_version != header_version_existing) {
+ die("header version mismatch, expected: %" PRIu32 " found %" PRIu32 "",
+ header_version, header_version_existing);
+ }
if (!ramdisk.empty()) die("cannot boot a boot.img *and* ramdisk");
@@ -477,13 +446,13 @@
fprintf(stderr,"creating boot image...\n");
int64_t bsize = 0;
- void* bdata = mkbootimg(kdata, ksize, kernel_offset,
+ boot_img_hdr_v1* bdata = mkbootimg(kdata, ksize, kernel_offset,
rdata, rsize, ramdisk_offset,
sdata, ssize, second_offset,
- page_size, base_addr, tags_offset, &bsize);
+ page_size, base_addr, tags_offset, header_version, &bsize);
if (bdata == nullptr) die("failed to create boot.img");
- if (cmdline) bootimg_set_cmdline((boot_img_hdr*) bdata, cmdline);
+ if (cmdline) bootimg_set_cmdline(bdata, cmdline);
fprintf(stderr, "creating boot image - %" PRId64 " bytes\n", bsize);
*sz = bsize;
@@ -539,7 +508,7 @@
die("make_temporary_directory not supported under Windows, sorry!");
}
-static int make_temporary_fd() {
+static int make_temporary_fd(const char* /*what*/) {
// TODO: reimplement to avoid leaking a FILE*.
return fileno(tmpfile());
}
@@ -555,18 +524,16 @@
static std::string make_temporary_directory() {
std::string result(make_temporary_template());
if (mkdtemp(&result[0]) == nullptr) {
- fprintf(stderr, "Unable to create temporary directory: %s\n", strerror(errno));
- return "";
+ die("unable to create temporary directory: %s", strerror(errno));
}
return result;
}
-static int make_temporary_fd() {
+static int make_temporary_fd(const char* what) {
std::string path_template(make_temporary_template());
int fd = mkstemp(&path_template[0]);
if (fd == -1) {
- fprintf(stderr, "Unable to create temporary file: %s\n", strerror(errno));
- return -1;
+ die("failed to create temporary file for %s: %s\n", what, strerror(errno));
}
unlink(path_template.c_str());
return fd;
@@ -576,16 +543,11 @@
static std::string create_fbemarker_tmpdir() {
std::string dir = make_temporary_directory();
- if (dir.empty()) {
- fprintf(stderr, "Unable to create local temp directory for FBE marker\n");
- return "";
- }
std::string marker_file = dir + "/" + convert_fbe_marker_filename;
int fd = open(marker_file.c_str(), O_CREAT | O_WRONLY | O_CLOEXEC, 0666);
if (fd == -1) {
- fprintf(stderr, "Unable to create FBE marker file %s locally: %d, %s\n",
- marker_file.c_str(), errno, strerror(errno));
- return "";
+ die("unable to create FBE marker file %s locally: %s",
+ marker_file.c_str(), strerror(errno));
}
close(fd);
return dir;
@@ -606,10 +568,7 @@
}
static int unzip_to_file(ZipArchiveHandle zip, const char* entry_name) {
- unique_fd fd(make_temporary_fd());
- if (fd == -1) {
- die("failed to create temporary file for '%s': %s", entry_name, strerror(errno));
- }
+ unique_fd fd(make_temporary_fd(entry_name));
ZipString zip_entry_name(entry_name);
ZipEntry zip_entry;
@@ -770,8 +729,8 @@
static int64_t get_target_sparse_limit(Transport* transport) {
std::string max_download_size;
if (!fb_getvar(transport, "max-download-size", &max_download_size) ||
- max_download_size.empty()) {
- fprintf(stderr, "target didn't report max-download-size\n");
+ max_download_size.empty()) {
+ verbose("target didn't report max-download-size");
return 0;
}
@@ -783,9 +742,7 @@
fprintf(stderr, "couldn't parse max-download-size '%s'\n", max_download_size.c_str());
return 0;
}
- if (limit > 0) {
- fprintf(stderr, "target reported max download size of %" PRId64 " bytes\n", limit);
- }
+ if (limit > 0) verbose("target reported max download size of %" PRId64 " bytes", limit);
return limit;
}
@@ -876,10 +833,7 @@
return;
}
- int fd = make_temporary_fd();
- if (fd == -1) {
- die("Failed to create temporary file for vbmeta rewriting");
- }
+ int fd = make_temporary_fd("vbmeta rewriting");
std::string data;
if (!android::base::ReadFdToString(buf->fd, &data)) {
@@ -1303,18 +1257,6 @@
return result;
}
-static void do_bypass_unlock_command(std::vector<std::string>* args) {
- if (args->empty()) syntax_error("missing unlock_bootloader request");
-
- std::string filename = next_arg(args);
-
- int64_t sz;
- void* data = load_file(filename.c_str(), &sz);
- if (data == nullptr) die("could not load '%s': %s", filename.c_str(), strerror(errno));
- fb_queue_download("unlock_message", data, sz);
- fb_queue_command("flashing unlock_bootloader", "unlocking bootloader");
-}
-
static void do_oem_command(const std::string& cmd, std::vector<std::string>* args) {
if (args->empty()) syntax_error("empty oem command");
@@ -1493,13 +1435,13 @@
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;
@@ -1517,14 +1459,16 @@
{"tags-offset", required_argument, 0, 't'},
{"help", no_argument, 0, 'h'},
{"unbuffered", no_argument, 0, 0},
- {"version", no_argument, 0, 0},
{"slot", required_argument, 0, 0},
{"set_active", optional_argument, 0, 'a'},
{"set-active", optional_argument, 0, 'a'},
{"skip-secondary", no_argument, 0, 0},
{"skip-reboot", no_argument, 0, 0},
+ {"verbose", no_argument, 0, 'v'},
+ {"version", no_argument, 0, 0},
{"disable-verity", no_argument, 0, 0},
{"disable-verification", no_argument, 0, 0},
+ {"header-version", required_argument, 0, 0},
#if !defined(_WIN32)
{"wipe-and-use-fbe", no_argument, 0, 0},
#endif
@@ -1534,7 +1478,7 @@
serial = getenv("ANDROID_SERIAL");
while (1) {
- int c = getopt_long(argc, argv, "wub:k:n:r:t:s:S:lc:i:m:ha::", longopts, &longindex);
+ int c = getopt_long(argc, argv, "vwub:k:n:r:t:s:S:lc:i:m:ha::", longopts, &longindex);
if (c < 0) {
break;
}
@@ -1589,6 +1533,9 @@
case 'u':
erase_first = false;
break;
+ case 'v':
+ set_verbose();
+ break;
case 'w':
wants_wipe = true;
break;
@@ -1617,10 +1564,10 @@
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:
@@ -1729,9 +1676,6 @@
if (what == "bootloader") {
wants_reboot = false;
wants_reboot_bootloader = true;
- } else if (what == "emergency") {
- wants_reboot = false;
- wants_reboot_emergency = true;
} else {
syntax_error("unknown reboot target %s", what.c_str());
}
@@ -1749,7 +1693,7 @@
std::string second_stage;
if (!args.empty()) second_stage = next_arg(&args);
- data = load_bootable_image(kernel, ramdisk, second_stage, &sz, cmdline);
+ data = load_bootable_image(kernel, ramdisk, second_stage, &sz, cmdline, header_version);
fb_queue_download("boot.img", data, sz);
fb_queue_command("boot", "booting");
} else if (command == "flash") {
@@ -1778,7 +1722,7 @@
std::string second_stage;
if (!args.empty()) second_stage = next_arg(&args);
- data = load_bootable_image(kernel, ramdisk, second_stage, &sz, cmdline);
+ data = load_bootable_image(kernel, ramdisk, second_stage, &sz, cmdline, header_version);
auto flashraw = [&](const std::string& partition) {
fb_queue_flash(partition, data, sz);
};
@@ -1834,12 +1778,8 @@
} else if (args.size() == 1 && (args[0] == "unlock" || args[0] == "lock" ||
args[0] == "unlock_critical" ||
args[0] == "lock_critical" ||
- args[0] == "get_unlock_ability" ||
- args[0] == "get_unlock_bootloader_nonce" ||
- args[0] == "lock_bootloader")) {
+ args[0] == "get_unlock_ability")) {
do_oem_command("flashing", &args);
- } else if (args.size() == 2 && args[0] == "unlock_bootloader") {
- do_bypass_unlock_command(&args);
} else {
syntax_error("unknown 'flashing' command %s", args[0].c_str());
}
@@ -1849,14 +1789,10 @@
}
if (wants_wipe) {
- fprintf(stderr, "wiping userdata...\n");
fb_queue_erase("userdata");
if (set_fbe_marker) {
- fprintf(stderr, "setting FBE marker...\n");
+ fprintf(stderr, "setting FBE marker on initial userdata...\n");
std::string initial_userdata_dir = create_fbemarker_tmpdir();
- if (initial_userdata_dir.empty()) {
- return 1;
- }
fb_perform_format(transport, "userdata", 1, "", "", initial_userdata_dir);
delete_fbemarker_tmpdir(initial_userdata_dir);
} else {
@@ -1865,7 +1801,6 @@
std::string cache_type;
if (fb_getvar(transport, "partition-type:cache", &cache_type) && !cache_type.empty()) {
- fprintf(stderr, "wiping cache...\n");
fb_queue_erase("cache");
fb_perform_format(transport, "cache", 1, "", "", "");
}
@@ -1879,9 +1814,6 @@
} else if (wants_reboot_bootloader) {
fb_queue_command("reboot-bootloader", "rebooting into bootloader");
fb_queue_wait_for_disconnect();
- } else if (wants_reboot_emergency) {
- fb_queue_command("reboot-emergency", "rebooting into emergency download (EDL) mode");
- fb_queue_wait_for_disconnect();
}
int status = fb_execute_queue(transport) ? EXIT_FAILURE : EXIT_SUCCESS;
diff --git a/fastboot/fastboot.h b/fastboot/fastboot.h
index a31057a..005ba5a 100644
--- a/fastboot/fastboot.h
+++ b/fastboot/fastboot.h
@@ -75,6 +75,7 @@
/* util stuff */
double now();
char* xstrdup(const char*);
+void set_verbose();
// These printf-like functions are implemented in terms of vsnprintf, so they
// use the same attribute for compile-time format string checking. On Windows,
@@ -90,6 +91,7 @@
#endif
void die(const char* fmt, ...) __attribute__((__noreturn__))
__attribute__((__format__(FASTBOOT_FORMAT_ARCHETYPE, 1, 2)));
+void verbose(const char* fmt, ...) __attribute__((__format__(FASTBOOT_FORMAT_ARCHETYPE, 1, 2)));
#undef FASTBOOT_FORMAT_ARCHETYPE
/* Current product */
diff --git a/fastboot/protocol.cpp b/fastboot/protocol.cpp
index c239861..133a2d0 100644
--- a/fastboot/protocol.cpp
+++ b/fastboot/protocol.cpp
@@ -75,18 +75,21 @@
}
if (!memcmp(status, "INFO", 4)) {
- fprintf(stderr,"(bootloader) %s\n", status + 4);
+ verbose("received INFO %s", status + 4);
+ fprintf(stderr, "(bootloader) %s\n", status + 4);
continue;
}
if (!memcmp(status, "OKAY", 4)) {
+ verbose("received OKAY %s", status + 4);
if (response) {
- strcpy(response, (char*) status + 4);
+ strcpy(response, status + 4);
}
return 0;
}
if (!memcmp(status, "FAIL", 4)) {
+ verbose("received FAIL %s", status + 4);
if (r > 4) {
g_error = android::base::StringPrintf("remote: %s", status + 4);
} else {
@@ -96,6 +99,7 @@
}
if (!memcmp(status, "DATA", 4) && size > 0){
+ verbose("received DATA %s", status + 4);
uint32_t dsize = strtol(status + 4, 0, 16);
if (dsize > size) {
g_error = android::base::StringPrintf("data size too large (%d)", dsize);
@@ -105,6 +109,7 @@
return dsize;
}
+ verbose("received unknown status code \"%4.4s\"", status);
g_error = "unknown status code";
transport->Close();
break;
@@ -124,6 +129,8 @@
response[0] = 0;
}
+ verbose("sending command \"%s\"", cmd.c_str());
+
if (transport->Write(cmd.c_str(), cmd.size()) != static_cast<int>(cmd.size())) {
g_error = android::base::StringPrintf("command write failed (%s)", strerror(errno));
transport->Close();
@@ -134,6 +141,8 @@
}
static int64_t _command_write_data(Transport* transport, const void* data, uint32_t size) {
+ verbose("sending data (%" PRIu32 " bytes)", size);
+
int64_t r = transport->Write(data, size);
if (r < 0) {
g_error = android::base::StringPrintf("data write failure (%s)", strerror(errno));
@@ -149,6 +158,8 @@
}
static int64_t _command_read_data(Transport* transport, void* data, uint32_t size) {
+ verbose("reading data (%" PRIu32 " bytes)", size);
+
int64_t r = transport->Read(data, size);
if (r < 0) {
g_error = android::base::StringPrintf("data read failure (%s)", strerror(errno));
diff --git a/fastboot/util.cpp b/fastboot/util.cpp
index fb085e7..140270f 100644
--- a/fastboot/util.cpp
+++ b/fastboot/util.cpp
@@ -35,6 +35,8 @@
#include "fastboot.h"
+static bool g_verbose = false;
+
double now() {
struct timeval tv;
gettimeofday(&tv, NULL);
@@ -44,13 +46,30 @@
void die(const char* fmt, ...) {
va_list ap;
va_start(ap, fmt);
- fprintf(stderr,"error: ");
+ fprintf(stderr, "fastboot: error: ");
vfprintf(stderr, fmt, ap);
- fprintf(stderr,"\n");
+ fprintf(stderr, "\n");
va_end(ap);
exit(EXIT_FAILURE);
}
+void set_verbose() {
+ g_verbose = true;
+}
+
+void verbose(const char* fmt, ...) {
+ if (!g_verbose) return;
+
+ if (*fmt != '\n') {
+ va_list ap;
+ va_start(ap, fmt);
+ fprintf(stderr, "fastboot: verbose: ");
+ vfprintf(stderr, fmt, ap);
+ va_end(ap);
+ }
+ fprintf(stderr, "\n");
+}
+
char* xstrdup(const char* s) {
char* result = strdup(s);
if (!result) die("out of memory");
diff --git a/fs_mgr/fs_mgr_format.cpp b/fs_mgr/fs_mgr_format.cpp
index 85a593f..63a6839 100644
--- a/fs_mgr/fs_mgr_format.cpp
+++ b/fs_mgr/fs_mgr_format.cpp
@@ -114,8 +114,19 @@
}
std::string size_str = std::to_string(dev_sz / 4096);
+ // clang-format off
const char* const args[] = {
- "/system/bin/make_f2fs", "-f", "-O", "encrypt", fs_blkdev, size_str.c_str(), nullptr};
+ "/system/bin/make_f2fs",
+ "-d1",
+ "-f",
+ "-O", "encrypt",
+ "-O", "quota",
+ "-w", "4096",
+ fs_blkdev,
+ size_str.c_str(),
+ nullptr
+ };
+ // clang-format on
return android_fork_execvp_ext(arraysize(args), const_cast<char**>(args), NULL, true,
LOG_KLOG, true, nullptr, nullptr, 0);
diff --git a/fs_mgr/fs_mgr_fstab.cpp b/fs_mgr/fs_mgr_fstab.cpp
index 72a65d2..3fbef9f 100644
--- a/fs_mgr/fs_mgr_fstab.cpp
+++ b/fs_mgr/fs_mgr_fstab.cpp
@@ -116,17 +116,21 @@
#define EM_ICE 2
#define EM_AES_256_CTS 3
#define EM_AES_256_HEH 4
+#define EM_SPECK_128_256_XTS 5
+#define EM_SPECK_128_256_CTS 6
static const struct flag_list file_contents_encryption_modes[] = {
{"aes-256-xts", EM_AES_256_XTS},
+ {"speck128/256-xts", EM_SPECK_128_256_XTS},
{"software", EM_AES_256_XTS}, /* alias for backwards compatibility */
- {"ice", EM_ICE}, /* hardware-specific inline cryptographic engine */
+ {"ice", EM_ICE}, /* hardware-specific inline cryptographic engine */
{0, 0},
};
static const struct flag_list file_names_encryption_modes[] = {
{"aes-256-cts", EM_AES_256_CTS},
{"aes-256-heh", EM_AES_256_HEH},
+ {"speck128/256-cts", EM_SPECK_128_256_CTS},
{0, 0},
};
diff --git a/init/Android.bp b/init/Android.bp
index 31c8efb..70a4ac6 100644
--- a/init/Android.bp
+++ b/init/Android.bp
@@ -127,9 +127,7 @@
"watchdogd.cpp",
],
whole_static_libs: ["libcap"],
- include_dirs: [
- "system/core/mkbootimg",
- ],
+ header_libs: ["bootimg_headers"],
proto: {
type: "lite",
export_proto_headers: true,
diff --git a/init/stable_properties.h b/init/stable_properties.h
index c8bdaa4..4714b57 100644
--- a/init/stable_properties.h
+++ b/init/stable_properties.h
@@ -35,10 +35,12 @@
"persist.bluetooth.btsnoopenable",
"persist.sys.crash_rcu",
"persist.sys.zram_enabled",
+ "ro.board.platform",
"ro.bootmode",
"ro.build.type",
"ro.debuggable",
"sys.boot_completed",
+ "sys.boot_from_charger_mode",
"sys.retaildemo.enabled",
"sys.shutdown.requested",
"sys.usb.config",
diff --git a/libbacktrace/UnwindStackMap.cpp b/libbacktrace/UnwindStackMap.cpp
index 9c6fed4..d2d6ab8 100644
--- a/libbacktrace/UnwindStackMap.cpp
+++ b/libbacktrace/UnwindStackMap.cpp
@@ -149,13 +149,12 @@
}
// Create the process memory from the stack data.
- uint64_t size = stack.end - stack.start;
- unwindstack::MemoryBuffer* memory = new unwindstack::MemoryBuffer;
- memory->Resize(size);
- memcpy(memory->GetPtr(0), stack.data, size);
- std::shared_ptr<unwindstack::Memory> shared_memory(memory);
-
- process_memory_.reset(new unwindstack::MemoryRange(shared_memory, 0, size, stack.start));
+ if (memory_ == nullptr) {
+ memory_ = new unwindstack::MemoryOfflineBuffer(stack.data, stack.start, stack.end);
+ process_memory_.reset(memory_);
+ } else {
+ memory_->Reset(stack.data, stack.start, stack.end);
+ }
return true;
}
diff --git a/libbacktrace/UnwindStackMap.h b/libbacktrace/UnwindStackMap.h
index ec0d9c1..039f4a2 100644
--- a/libbacktrace/UnwindStackMap.h
+++ b/libbacktrace/UnwindStackMap.h
@@ -79,6 +79,9 @@
bool Build(const std::vector<backtrace_map_t>& maps);
bool CreateProcessMemory(const backtrace_stackinfo_t& stack);
+
+ private:
+ unwindstack::MemoryOfflineBuffer* memory_ = nullptr;
};
#endif // _LIBBACKTRACE_UNWINDSTACK_MAP_H
diff --git a/libunwindstack/Android.bp b/libunwindstack/Android.bp
index 0d43f87..6868f18 100644
--- a/libunwindstack/Android.bp
+++ b/libunwindstack/Android.bp
@@ -155,6 +155,7 @@
"tests/MemoryFake.cpp",
"tests/MemoryFileTest.cpp",
"tests/MemoryLocalTest.cpp",
+ "tests/MemoryOfflineBufferTest.cpp",
"tests/MemoryOfflineTest.cpp",
"tests/MemoryRangeTest.cpp",
"tests/MemoryRemoteTest.cpp",
diff --git a/libunwindstack/Memory.cpp b/libunwindstack/Memory.cpp
index d4ba680..beb2aad 100644
--- a/libunwindstack/Memory.cpp
+++ b/libunwindstack/Memory.cpp
@@ -345,6 +345,25 @@
return memory_->Read(addr, dst, size);
}
+MemoryOfflineBuffer::MemoryOfflineBuffer(const uint8_t* data, uint64_t start, uint64_t end)
+ : data_(data), start_(start), end_(end) {}
+
+void MemoryOfflineBuffer::Reset(const uint8_t* data, uint64_t start, uint64_t end) {
+ data_ = data;
+ start_ = start;
+ end_ = end;
+}
+
+size_t MemoryOfflineBuffer::Read(uint64_t addr, void* dst, size_t size) {
+ if (addr < start_ || addr >= end_) {
+ return 0;
+ }
+
+ size_t read_length = std::min(size, static_cast<size_t>(end_ - addr));
+ memcpy(dst, &data_[addr - start_], read_length);
+ return read_length;
+}
+
MemoryOfflineParts::~MemoryOfflineParts() {
for (auto memory : memories_) {
delete memory;
diff --git a/libunwindstack/include/unwindstack/Memory.h b/libunwindstack/include/unwindstack/Memory.h
index 19bce04..c0c07f4 100644
--- a/libunwindstack/include/unwindstack/Memory.h
+++ b/libunwindstack/include/unwindstack/Memory.h
@@ -151,6 +151,21 @@
std::unique_ptr<MemoryRange> memory_;
};
+class MemoryOfflineBuffer : public Memory {
+ public:
+ MemoryOfflineBuffer(const uint8_t* data, uint64_t start, uint64_t end);
+ virtual ~MemoryOfflineBuffer() = default;
+
+ void Reset(const uint8_t* data, uint64_t start, uint64_t end);
+
+ size_t Read(uint64_t addr, void* dst, size_t size) override;
+
+ private:
+ const uint8_t* data_;
+ uint64_t start_;
+ uint64_t end_;
+};
+
class MemoryOfflineParts : public Memory {
public:
MemoryOfflineParts() = default;
diff --git a/libunwindstack/tests/MemoryOfflineBufferTest.cpp b/libunwindstack/tests/MemoryOfflineBufferTest.cpp
new file mode 100644
index 0000000..f022884
--- /dev/null
+++ b/libunwindstack/tests/MemoryOfflineBufferTest.cpp
@@ -0,0 +1,97 @@
+/*
+ * 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 <vector>
+
+#include <gtest/gtest.h>
+
+#include <unwindstack/Memory.h>
+
+#include "LogFake.h"
+
+namespace unwindstack {
+
+class MemoryOfflineBufferTest : public ::testing::Test {
+ protected:
+ void SetUp() override {
+ ResetLogs();
+ memory_.reset(new MemoryOfflineBuffer(buffer_.data(), kStart, kEnd));
+ }
+
+ static void SetUpTestCase() {
+ buffer_.resize(kLength);
+ for (size_t i = 0; i < kLength; i++) {
+ buffer_[i] = i % 189;
+ }
+ }
+
+ std::unique_ptr<MemoryOfflineBuffer> memory_;
+
+ static constexpr size_t kLength = 0x2000;
+ static constexpr uint64_t kStart = 0x1000;
+ static constexpr uint64_t kEnd = kStart + kLength;
+ static std::vector<uint8_t> buffer_;
+};
+
+std::vector<uint8_t> MemoryOfflineBufferTest::buffer_;
+
+static void VerifyBuffer(uint8_t* buffer, size_t start_value, size_t length) {
+ for (size_t i = 0; i < length; i++) {
+ ASSERT_EQ((start_value + i) % 189, buffer[i]) << "Failed at byte " << i;
+ }
+}
+
+TEST_F(MemoryOfflineBufferTest, read_out_of_bounds) {
+ std::vector<uint8_t> buffer(1024);
+ ASSERT_FALSE(memory_->ReadFully(0, buffer.data(), 1));
+ ASSERT_FALSE(memory_->ReadFully(0xfff, buffer.data(), 1));
+ ASSERT_FALSE(memory_->ReadFully(0xfff, buffer.data(), 2));
+ ASSERT_FALSE(memory_->ReadFully(0x3000, buffer.data(), 1));
+ ASSERT_FALSE(memory_->ReadFully(0x3001, buffer.data(), 1));
+}
+
+TEST_F(MemoryOfflineBufferTest, read) {
+ std::vector<uint8_t> buffer(1024);
+ ASSERT_TRUE(memory_->ReadFully(kStart, buffer.data(), 10));
+ ASSERT_NO_FATAL_FAILURE(VerifyBuffer(buffer.data(), 0, 10));
+
+ ASSERT_TRUE(memory_->ReadFully(kStart + 555, buffer.data(), 40));
+ ASSERT_NO_FATAL_FAILURE(VerifyBuffer(buffer.data(), 555, 40));
+
+ ASSERT_TRUE(memory_->ReadFully(kStart + kLength - 105, buffer.data(), 105));
+ ASSERT_NO_FATAL_FAILURE(VerifyBuffer(buffer.data(), kLength - 105, 105));
+}
+
+TEST_F(MemoryOfflineBufferTest, read_past_end) {
+ std::vector<uint8_t> buffer(1024);
+ ASSERT_EQ(100U, memory_->Read(kStart + kLength - 100, buffer.data(), buffer.size()));
+ VerifyBuffer(buffer.data(), kLength - 100, 100);
+}
+
+TEST_F(MemoryOfflineBufferTest, read_after_reset) {
+ std::vector<uint8_t> buffer(1024);
+ ASSERT_TRUE(memory_->ReadFully(kStart, buffer.data(), 100));
+ ASSERT_NO_FATAL_FAILURE(VerifyBuffer(buffer.data(), 0, 100));
+
+ memory_->Reset(&buffer_[10], 0x12000, 0x13000);
+ ASSERT_TRUE(memory_->ReadFully(0x12000, buffer.data(), 100));
+ ASSERT_NO_FATAL_FAILURE(VerifyBuffer(buffer.data(), 10, 100));
+
+ ASSERT_EQ(50U, memory_->Read(0x13000 - 50, buffer.data(), buffer.size()));
+ ASSERT_NO_FATAL_FAILURE(VerifyBuffer(buffer.data(), 0x1000 - 50 + 10, 50));
+}
+
+} // namespace unwindstack
diff --git a/mkbootimg/Android.bp b/mkbootimg/Android.bp
new file mode 100644
index 0000000..b494346
--- /dev/null
+++ b/mkbootimg/Android.bp
@@ -0,0 +1,32 @@
+// Copyright 2012 The Android Open Source Project
+
+cc_library_headers {
+ name: "libmkbootimg_abi_headers",
+ vendor_available: true,
+ export_include_dirs: ["include"],
+}
+
+cc_library_headers {
+ name: "bootimg_headers",
+ vendor_available: true,
+ export_include_dirs: ["include/bootimg"],
+ host_supported: true,
+ target: {
+ windows: {
+ enabled: true,
+ },
+ },
+}
+
+cc_library {
+ name: "libmkbootimg_abi_check",
+ vendor_available: true,
+ vndk: {
+ enabled: true,
+ },
+ srcs: [
+ "mkbootimg_dummy.cpp",
+ ],
+ header_libs: ["libmkbootimg_abi_headers"],
+ export_header_lib_headers: ["libmkbootimg_abi_headers"],
+}
diff --git a/mkbootimg/include/abi_check/mkbootimg_abi_check.h b/mkbootimg/include/abi_check/mkbootimg_abi_check.h
new file mode 100644
index 0000000..d478aba
--- /dev/null
+++ b/mkbootimg/include/abi_check/mkbootimg_abi_check.h
@@ -0,0 +1,28 @@
+/*
+ * 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 <bootimg/bootimg.h>
+
+// This header has been created for the following reaons:
+// 1) In order for a change in a user defined type to be classified as API /
+// ABI breaking, it needs to be referenced by an 'exported interface'
+// (in this case the function mkbootimg_dummy).
+// 2) Since 'mkbootimg_dummy' needs to be exported, we need to have it
+// exposed through a public header.
+// 3) It is desirable not to pollute bootimg.h with interfaces which are not
+// 'used' in reality by on device binaries. Furthermore, bootimg.h might
+// be exported by a library in the future, so we must avoid polluting it.
+void mkbootimg_dummy(boot_img_hdr*);
diff --git a/mkbootimg/bootimg.h b/mkbootimg/include/bootimg/bootimg.h
similarity index 91%
rename from mkbootimg/bootimg.h
rename to mkbootimg/include/bootimg/bootimg.h
index 1be8c22..4311b46 100644
--- a/mkbootimg/bootimg.h
+++ b/mkbootimg/include/bootimg/bootimg.h
@@ -2,16 +2,16 @@
**
** 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
+** 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
+** 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
+** 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.
*/
@@ -34,17 +34,17 @@
struct boot_img_hdr_v0 {
uint8_t magic[BOOT_MAGIC_SIZE];
- uint32_t kernel_size; /* size in bytes */
- uint32_t kernel_addr; /* physical load addr */
+ uint32_t kernel_size; /* size in bytes */
+ uint32_t kernel_addr; /* physical load addr */
uint32_t ramdisk_size; /* size in bytes */
uint32_t ramdisk_addr; /* physical load addr */
- uint32_t second_size; /* size in bytes */
- uint32_t second_addr; /* physical load addr */
+ uint32_t second_size; /* size in bytes */
+ uint32_t second_addr; /* physical load addr */
- uint32_t tags_addr; /* physical addr for kernel tags */
- uint32_t page_size; /* flash page size we assume */
+ uint32_t tags_addr; /* physical addr for kernel tags */
+ uint32_t page_size; /* flash page size we assume */
/*
* version for the boot image header.
*/
diff --git a/mkbootimg/mkbootimg_dummy.cpp b/mkbootimg/mkbootimg_dummy.cpp
new file mode 100644
index 0000000..410d379
--- /dev/null
+++ b/mkbootimg/mkbootimg_dummy.cpp
@@ -0,0 +1,24 @@
+/*
+ * 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 <abi_check/mkbootimg_abi_check.h>
+
+void mkbootimg_dummy(boot_img_hdr* hdr) {
+ // TODO: Hack to trigger abi checks, remove this.
+ if (hdr) {
+ hdr--;
+ }
+}
diff --git a/rootdir/etc/ld.config.txt b/rootdir/etc/ld.config.txt
index 94465f4..ba96cc8 100644
--- a/rootdir/etc/ld.config.txt
+++ b/rootdir/etc/ld.config.txt
@@ -218,13 +218,20 @@
namespace.vndk.asan.permitted.paths += /data/asan/system/${LIB}/vndk-sp%VNDK_VER%/hw
namespace.vndk.asan.permitted.paths += /system/${LIB}/vndk-sp%VNDK_VER%/hw
+# The "vndk" namespace links to "default" namespace for LLNDK libs and links to
+# "sphal" namespace for vendor libs. The ordering matters. The "default"
+# namespace has higher priority than the "sphal" namespace.
+namespace.vndk.links = default,sphal
+
# When these NDK libs are required inside this namespace, then it is redirected
# to the default namespace. This is possible since their ABI is stable across
# Android releases.
-namespace.vndk.links = default
namespace.vndk.link.default.shared_libs = %LLNDK_LIBRARIES%
namespace.vndk.link.default.shared_libs += %SANITIZER_RUNTIME_LIBRARIES%
+# Allow VNDK-SP extensions to use vendor libraries
+namespace.vndk.link.sphal.allow_all_shared_libs = true
+
###############################################################################
# Namespace config for vendor processes. In O, no restriction is enforced for
# them. However, in O-MR1, access to /system/${LIB} will not be allowed to