Merge "liblp: Allow "flashing" files on the host."
diff --git a/adb/socket_spec.cpp b/adb/socket_spec.cpp
index 98468b5..27e8c46 100644
--- a/adb/socket_spec.cpp
+++ b/adb/socket_spec.cpp
@@ -272,7 +272,9 @@
if (hostname.empty() && gListenAll) {
result = network_inaddr_any_server(port, SOCK_STREAM, error);
} else if (tcp_host_is_local(hostname)) {
- result = network_loopback_server(port, SOCK_STREAM, error);
+ result = network_loopback_server(port, SOCK_STREAM, error, true);
+ } else if (hostname == "::1") {
+ result = network_loopback_server(port, SOCK_STREAM, error, false);
} else {
// TODO: Implement me.
*error = "listening on specified hostname currently unsupported";
diff --git a/adb/sysdeps/network.h b/adb/sysdeps/network.h
index 83ce371..fadd155 100644
--- a/adb/sysdeps/network.h
+++ b/adb/sysdeps/network.h
@@ -19,4 +19,4 @@
#include <string>
int network_loopback_client(int port, int type, std::string* error);
-int network_loopback_server(int port, int type, std::string* error);
+int network_loopback_server(int port, int type, std::string* error, bool prefer_ipv4);
diff --git a/adb/sysdeps/posix/network.cpp b/adb/sysdeps/posix/network.cpp
index c5c2275..a4d9013 100644
--- a/adb/sysdeps/posix/network.cpp
+++ b/adb/sysdeps/posix/network.cpp
@@ -119,12 +119,15 @@
return s.release();
}
-int network_loopback_server(int port, int type, std::string* error) {
- int rc = _network_loopback_server(false, port, type, error);
+int network_loopback_server(int port, int type, std::string* error, bool prefer_ipv4) {
+ int rc = -1;
+ if (prefer_ipv4) {
+ rc = _network_loopback_server(false, port, type, error);
+ }
- // Only attempt to listen on IPv6 if IPv4 is unavailable.
+ // Only attempt to listen on IPv6 if IPv4 is unavailable or prefer_ipv4 is false
// We don't want to start an IPv6 server if there's already an IPv4 one running.
- if (rc == -1 && (errno == EADDRNOTAVAIL || errno == EAFNOSUPPORT)) {
+ if (rc == -1 && (errno == EADDRNOTAVAIL || errno == EAFNOSUPPORT || !prefer_ipv4)) {
return _network_loopback_server(true, port, type, error);
}
return rc;
diff --git a/adb/sysdeps_win32.cpp b/adb/sysdeps_win32.cpp
index 4d6cf3d..d9cc36f 100644
--- a/adb/sysdeps_win32.cpp
+++ b/adb/sysdeps_win32.cpp
@@ -920,7 +920,8 @@
return fd;
}
-int network_loopback_server(int port, int type, std::string* error) {
+int network_loopback_server(int port, int type, std::string* error, bool prefer_ipv4) {
+ // TODO implement IPv6 support on windows
return _network_server(port, type, INADDR_LOOPBACK, error);
}
@@ -1132,7 +1133,7 @@
int local_port = -1;
std::string error;
- server = network_loopback_server(0, SOCK_STREAM, &error);
+ server = network_loopback_server(0, SOCK_STREAM, &error, true);
if (server < 0) {
D("adb_socketpair: failed to create server: %s", error.c_str());
goto fail;
diff --git a/adb/test_adb.py b/adb/test_adb.py
index 8272722..3d6de26 100755
--- a/adb/test_adb.py
+++ b/adb/test_adb.py
@@ -281,6 +281,37 @@
subprocess.check_output(["adb", "-P", str(port), "kill-server"],
stderr=subprocess.STDOUT)
+ @unittest.skipUnless(
+ os.name == "posix",
+ "adb doesn't yet support IPv6 on Windows",
+ )
+ def test_starts_on_ipv6_localhost(self):
+ """
+ Tests that the server can start up on ::1 and that it's accessible
+ """
+ server_port = 5037
+ # Kill any existing server on this non-default port.
+ subprocess.check_output(
+ ["adb", "-P", str(server_port), "kill-server"],
+ stderr=subprocess.STDOUT,
+ )
+ try:
+ subprocess.check_output(
+ ["adb", "-L", "tcp:[::1]:{}".format(server_port), "server"],
+ stderr=subprocess.STDOUT,
+ )
+ with fake_adbd() as (port, _):
+ with adb_connect(self, serial="localhost:{}".format(port)):
+ pass
+ finally:
+ # If we started a server, kill it.
+ subprocess.check_output(
+ ["adb", "-P", str(server_port), "kill-server"],
+ stderr=subprocess.STDOUT,
+ )
+
+
+
class EmulatorTest(unittest.TestCase):
"""Tests for the emulator connection."""
diff --git a/base/Android.bp b/base/Android.bp
index 25ae535..aeb8864 100644
--- a/base/Android.bp
+++ b/base/Android.bp
@@ -58,6 +58,7 @@
"file.cpp",
"logging.cpp",
"mapped_file.cpp",
+ "parsebool.cpp",
"parsenetaddress.cpp",
"process.cpp",
"properties.cpp",
@@ -149,6 +150,7 @@
"macros_test.cpp",
"mapped_file_test.cpp",
"parsedouble_test.cpp",
+ "parsebool_test.cpp",
"parseint_test.cpp",
"parsenetaddress_test.cpp",
"process_test.cpp",
diff --git a/base/include/android-base/parsebool.h b/base/include/android-base/parsebool.h
new file mode 100644
index 0000000..b2bd021
--- /dev/null
+++ b/base/include/android-base/parsebool.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2019 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 <string_view>
+
+namespace android {
+namespace base {
+
+// Parse the given string as yes or no inactivation of some sort. Return one of the
+// ParseBoolResult enumeration values.
+//
+// The following values parse as true:
+//
+// 1
+// on
+// true
+// y
+// yes
+//
+//
+// The following values parse as false:
+//
+// 0
+// false
+// n
+// no
+// off
+//
+// Anything else is a parse error.
+//
+// The purpose of this function is to have a single canonical parser for yes-or-no indications
+// throughout the system.
+
+enum class ParseBoolResult {
+ kError,
+ kFalse,
+ kTrue,
+};
+
+ParseBoolResult ParseBool(std::string_view s);
+
+} // namespace base
+} // namespace android
diff --git a/base/parsebool.cpp b/base/parsebool.cpp
new file mode 100644
index 0000000..ff96fe9
--- /dev/null
+++ b/base/parsebool.cpp
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2019 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/parsebool.h"
+#include <errno.h>
+
+namespace android {
+namespace base {
+
+ParseBoolResult ParseBool(std::string_view s) {
+ if (s == "1" || s == "y" || s == "yes" || s == "on" || s == "true") {
+ return ParseBoolResult::kTrue;
+ }
+ if (s == "0" || s == "n" || s == "no" || s == "off" || s == "false") {
+ return ParseBoolResult::kFalse;
+ }
+ return ParseBoolResult::kError;
+}
+
+} // namespace base
+} // namespace android
diff --git a/base/parsebool_test.cpp b/base/parsebool_test.cpp
new file mode 100644
index 0000000..a081994
--- /dev/null
+++ b/base/parsebool_test.cpp
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2019 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/parsebool.h"
+
+#include <errno.h>
+
+#include <gtest/gtest.h>
+#include <string_view>
+
+using android::base::ParseBool;
+using android::base::ParseBoolResult;
+
+TEST(parsebool, true_) {
+ static const char* yes[] = {
+ "1", "on", "true", "y", "yes",
+ };
+ for (const char* s : yes) {
+ ASSERT_EQ(ParseBoolResult::kTrue, ParseBool(s));
+ }
+}
+
+TEST(parsebool, false_) {
+ static const char* no[] = {
+ "0", "false", "n", "no", "off",
+ };
+ for (const char* s : no) {
+ ASSERT_EQ(ParseBoolResult::kFalse, ParseBool(s));
+ }
+}
+
+TEST(parsebool, invalid) {
+ ASSERT_EQ(ParseBoolResult::kError, ParseBool("blarg"));
+ ASSERT_EQ(ParseBoolResult::kError, ParseBool(""));
+}
diff --git a/base/properties.cpp b/base/properties.cpp
index d5a5918..4731bf2 100644
--- a/base/properties.cpp
+++ b/base/properties.cpp
@@ -28,19 +28,22 @@
#include <map>
#include <string>
+#include <android-base/parsebool.h>
#include <android-base/parseint.h>
namespace android {
namespace base {
bool GetBoolProperty(const std::string& key, bool default_value) {
- std::string value = GetProperty(key, "");
- if (value == "1" || value == "y" || value == "yes" || value == "on" || value == "true") {
- return true;
- } else if (value == "0" || value == "n" || value == "no" || value == "off" || value == "false") {
- return false;
+ switch (ParseBool(GetProperty(key, ""))) {
+ case ParseBoolResult::kError:
+ return default_value;
+ case ParseBoolResult::kFalse:
+ return false;
+ case ParseBoolResult::kTrue:
+ return true;
}
- return default_value;
+ __builtin_unreachable();
}
template <typename T>
diff --git a/init/subcontext.cpp b/init/subcontext.cpp
index e55265b..bebcc77 100644
--- a/init/subcontext.cpp
+++ b/init/subcontext.cpp
@@ -209,8 +209,12 @@
PLOG(FATAL) << "Could not dup child_fd";
}
- if (setexeccon(context_.c_str()) < 0) {
- PLOG(FATAL) << "Could not set execcon for '" << context_ << "'";
+ // We don't switch contexts if we're running the unit tests. We don't use std::optional,
+ // since we still need a real context string to pass to the builtin functions.
+ if (context_ != kTestContext) {
+ if (setexeccon(context_.c_str()) < 0) {
+ PLOG(FATAL) << "Could not set execcon for '" << context_ << "'";
+ }
}
auto init_path = GetExecutablePath();
diff --git a/init/subcontext.h b/init/subcontext.h
index bcaad29..5e1d8a8 100644
--- a/init/subcontext.h
+++ b/init/subcontext.h
@@ -32,6 +32,7 @@
static constexpr const char kInitContext[] = "u:r:init:s0";
static constexpr const char kVendorContext[] = "u:r:vendor_init:s0";
+static constexpr const char kTestContext[] = "test-test-test";
class Subcontext {
public:
diff --git a/init/subcontext_test.cpp b/init/subcontext_test.cpp
index 9c1a788..2e5a256 100644
--- a/init/subcontext_test.cpp
+++ b/init/subcontext_test.cpp
@@ -39,24 +39,12 @@
namespace android {
namespace init {
-// I would use test fixtures, but I cannot skip the test if not root with them, so instead we have
-// this test runner.
template <typename F>
void RunTest(F&& test_function) {
- if (getuid() != 0) {
- GTEST_SKIP() << "Skipping test, must be run as root.";
- return;
- }
-
- char* context;
- ASSERT_EQ(0, getcon(&context));
- auto context_string = std::string(context);
- free(context);
-
- auto subcontext = Subcontext({"dummy_path"}, context_string);
+ auto subcontext = Subcontext({"dummy_path"}, kTestContext);
ASSERT_NE(0, subcontext.pid());
- test_function(subcontext, context_string);
+ test_function(subcontext);
if (subcontext.pid() > 0) {
kill(subcontext.pid(), SIGTERM);
@@ -65,7 +53,7 @@
}
TEST(subcontext, CheckDifferentPid) {
- RunTest([](auto& subcontext, auto& context_string) {
+ RunTest([](auto& subcontext) {
auto result = subcontext.Execute(std::vector<std::string>{"return_pids_as_error"});
ASSERT_FALSE(result);
@@ -78,7 +66,12 @@
}
TEST(subcontext, SetProp) {
- RunTest([](auto& subcontext, auto& context_string) {
+ if (getuid() != 0) {
+ GTEST_SKIP() << "Skipping test, must be run as root.";
+ return;
+ }
+
+ RunTest([](auto& subcontext) {
SetProperty("init.test.subcontext", "fail");
WaitForProperty("init.test.subcontext", "fail");
@@ -95,7 +88,7 @@
}
TEST(subcontext, MultipleCommands) {
- RunTest([](auto& subcontext, auto& context_string) {
+ RunTest([](auto& subcontext) {
auto first_pid = subcontext.pid();
auto expected_words = std::vector<std::string>{
@@ -122,7 +115,7 @@
}
TEST(subcontext, RecoverAfterAbort) {
- RunTest([](auto& subcontext, auto& context_string) {
+ RunTest([](auto& subcontext) {
auto first_pid = subcontext.pid();
auto result = subcontext.Execute(std::vector<std::string>{"cause_log_fatal"});
@@ -136,10 +129,10 @@
}
TEST(subcontext, ContextString) {
- RunTest([](auto& subcontext, auto& context_string) {
+ RunTest([](auto& subcontext) {
auto result = subcontext.Execute(std::vector<std::string>{"return_context_as_error"});
ASSERT_FALSE(result);
- ASSERT_EQ(context_string, result.error().message());
+ ASSERT_EQ(kTestContext, result.error().message());
});
}
@@ -147,7 +140,7 @@
static constexpr const char kTestShutdownCommand[] = "reboot,test-shutdown-command";
static std::string trigger_shutdown_command;
trigger_shutdown = [](const std::string& command) { trigger_shutdown_command = command; };
- RunTest([](auto& subcontext, auto& context_string) {
+ RunTest([](auto& subcontext) {
auto result = subcontext.Execute(
std::vector<std::string>{"trigger_shutdown", kTestShutdownCommand});
ASSERT_TRUE(result);
@@ -156,7 +149,7 @@
}
TEST(subcontext, ExpandArgs) {
- RunTest([](auto& subcontext, auto& context_string) {
+ RunTest([](auto& subcontext) {
auto args = std::vector<std::string>{
"first",
"${ro.hardware}",
@@ -172,7 +165,7 @@
}
TEST(subcontext, ExpandArgsFailure) {
- RunTest([](auto& subcontext, auto& context_string) {
+ RunTest([](auto& subcontext) {
auto args = std::vector<std::string>{
"first",
"${",
diff --git a/libunwindstack/Android.bp b/libunwindstack/Android.bp
index 2573b1c..512c962 100644
--- a/libunwindstack/Android.bp
+++ b/libunwindstack/Android.bp
@@ -77,6 +77,7 @@
],
cflags: [
+ "-DDEXFILE_SUPPORT",
"-Wexit-time-destructors",
],
@@ -89,20 +90,18 @@
],
},
vendor: {
- cflags: ["-DNO_LIBDEXFILE_SUPPORT"],
+ cflags: ["-UDEXFILE_SUPPORT"],
exclude_srcs: [
"DexFile.cpp",
- "DexFiles.cpp",
],
exclude_shared_libs: [
"libdexfile_support",
],
},
recovery: {
- cflags: ["-DNO_LIBDEXFILE_SUPPORT"],
+ cflags: ["-UDEXFILE_SUPPORT"],
exclude_srcs: [
"DexFile.cpp",
- "DexFiles.cpp",
],
exclude_shared_libs: [
"libdexfile_support",
diff --git a/libunwindstack/DexFiles.cpp b/libunwindstack/DexFiles.cpp
index 63a77e5..2057fad 100644
--- a/libunwindstack/DexFiles.cpp
+++ b/libunwindstack/DexFiles.cpp
@@ -27,10 +27,21 @@
#include <unwindstack/Maps.h>
#include <unwindstack/Memory.h>
+#if defined(DEXFILE_SUPPORT)
#include "DexFile.h"
+#endif
namespace unwindstack {
+#if !defined(DEXFILE_SUPPORT)
+// Empty class definition.
+class DexFile {
+ public:
+ DexFile() = default;
+ virtual ~DexFile() = default;
+};
+#endif
+
struct DEXFileEntry32 {
uint32_t next;
uint32_t prev;
@@ -128,6 +139,7 @@
FindAndReadVariable(maps, "__dex_debug_descriptor");
}
+#if defined(DEXFILE_SUPPORT)
DexFile* DexFiles::GetDexFile(uint64_t dex_file_offset, MapInfo* info) {
// Lock while processing the data.
DexFile* dex_file;
@@ -141,6 +153,11 @@
}
return dex_file;
}
+#else
+DexFile* DexFiles::GetDexFile(uint64_t, MapInfo*) {
+ return nullptr;
+}
+#endif
bool DexFiles::GetAddr(size_t index, uint64_t* addr) {
if (index < addrs_.size()) {
@@ -154,6 +171,7 @@
return false;
}
+#if defined(DEXFILE_SUPPORT)
void DexFiles::GetMethodInformation(Maps* maps, MapInfo* info, uint64_t dex_pc,
std::string* method_name, uint64_t* method_offset) {
std::lock_guard<std::mutex> guard(lock_);
@@ -175,5 +193,8 @@
}
}
}
+#else
+void DexFiles::GetMethodInformation(Maps*, MapInfo*, uint64_t, std::string*, uint64_t*) {}
+#endif
} // namespace unwindstack
diff --git a/libunwindstack/Unwinder.cpp b/libunwindstack/Unwinder.cpp
index 0b9b85c..1bb0319 100644
--- a/libunwindstack/Unwinder.cpp
+++ b/libunwindstack/Unwinder.cpp
@@ -34,9 +34,7 @@
#include <unwindstack/Memory.h>
#include <unwindstack/Unwinder.h>
-#if !defined(NO_LIBDEXFILE_SUPPORT)
#include <unwindstack/DexFiles.h>
-#endif
// Use the demangler from libc++.
extern "C" char* __cxa_demangle(const char*, char*, size_t*, int* status);
@@ -84,7 +82,7 @@
return;
}
-#if !defined(NO_LIBDEXFILE_SUPPORT)
+#if defined(DEXFILE_SUPPORT)
if (dex_files_ == nullptr) {
return;
}
@@ -367,12 +365,10 @@
jit_debug_ = jit_debug;
}
-#if !defined(NO_LIBDEXFILE_SUPPORT)
void Unwinder::SetDexFiles(DexFiles* dex_files, ArchEnum arch) {
dex_files->SetArch(arch);
dex_files_ = dex_files;
}
-#endif
bool UnwinderFromPid::Init(ArchEnum arch) {
if (pid_ == getpid()) {
@@ -390,7 +386,7 @@
jit_debug_ptr_.reset(new JitDebug(process_memory_));
jit_debug_ = jit_debug_ptr_.get();
SetJitDebug(jit_debug_, arch);
-#if !defined(NO_LIBDEXFILE_SUPPORT)
+#if defined(DEXFILE_SUPPORT)
dex_files_ptr_.reset(new DexFiles(process_memory_));
dex_files_ = dex_files_ptr_.get();
SetDexFiles(dex_files_, arch);
diff --git a/libunwindstack/include/unwindstack/Unwinder.h b/libunwindstack/include/unwindstack/Unwinder.h
index 11ad9de..67762c0 100644
--- a/libunwindstack/include/unwindstack/Unwinder.h
+++ b/libunwindstack/include/unwindstack/Unwinder.h
@@ -107,9 +107,7 @@
void SetDisplayBuildID(bool display_build_id) { display_build_id_ = display_build_id; }
-#if !defined(NO_LIBDEXFILE_SUPPORT)
void SetDexFiles(DexFiles* dex_files, ArchEnum arch);
-#endif
bool elf_from_memory_not_file() { return elf_from_memory_not_file_; }
@@ -128,9 +126,7 @@
std::vector<FrameData> frames_;
std::shared_ptr<Memory> process_memory_;
JitDebug* jit_debug_ = nullptr;
-#if !defined(NO_LIBDEXFILE_SUPPORT)
DexFiles* dex_files_ = nullptr;
-#endif
bool resolve_names_ = true;
bool embedded_soname_ = true;
bool display_build_id_ = false;
@@ -151,9 +147,7 @@
pid_t pid_;
std::unique_ptr<Maps> maps_ptr_;
std::unique_ptr<JitDebug> jit_debug_ptr_;
-#if !defined(NO_LIBDEXFILE_SUPPORT)
std::unique_ptr<DexFiles> dex_files_ptr_;
-#endif
};
} // namespace unwindstack
diff --git a/logd/LogBuffer.cpp b/logd/LogBuffer.cpp
index ba05a06..834b20b 100644
--- a/logd/LogBuffer.cpp
+++ b/logd/LogBuffer.cpp
@@ -638,6 +638,8 @@
if (stats.sizes(id) > (2 * log_buffer_size(id))) { // +100%
// A misbehaving or slow reader has its connection
// dropped if we hit too much memory pressure.
+ android::prdebug("Kicking blocked reader, pid %d, from LogBuffer::kickMe()\n",
+ me->mClient->getPid());
me->release_Locked();
} else if (me->mTimeout.tv_sec || me->mTimeout.tv_nsec) {
// Allow a blocked WRAP timeout reader to
@@ -645,6 +647,9 @@
me->triggerReader_Locked();
} else {
// tell slow reader to skip entries to catch up
+ android::prdebug(
+ "Skipping %lu entries from slow reader, pid %d, from LogBuffer::kickMe()\n",
+ pruneRows, me->mClient->getPid());
me->triggerSkip_Locked(id, pruneRows);
}
}
@@ -1051,6 +1056,9 @@
LogTimeEntry* entry = times->get();
// Killer punch
if (entry->isWatching(id)) {
+ android::prdebug(
+ "Kicking blocked reader, pid %d, from LogBuffer::clear()\n",
+ entry->mClient->getPid());
entry->release_Locked();
}
times++;