Merge "Add ParseFloat (in parsedouble.h)."
diff --git a/adb/Android.bp b/adb/Android.bp
index 906c5e3..dabc5ce 100644
--- a/adb/Android.bp
+++ b/adb/Android.bp
@@ -449,7 +449,7 @@
test_suites: ["device-tests"],
}
-python_binary_host {
+python_test_host {
name: "adb_integration_test_adb",
main: "test_adb.py",
srcs: [
@@ -458,6 +458,8 @@
libs: [
"adb_py",
],
+ test_config: "adb_integration_test_adb.xml",
+ test_suites: ["general-tests"],
version: {
py2: {
enabled: true,
diff --git a/adb/adb_integration_test_adb.xml b/adb/adb_integration_test_adb.xml
new file mode 100644
index 0000000..e722956
--- /dev/null
+++ b/adb/adb_integration_test_adb.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+<configuration description="Config to run adb integration tests">
+ <option name="test-suite-tag" value="adb_tests" />
+ <option name="test-suite-tag" value="adb_integration" />
+ <target_preparer class="com.android.tradefed.targetprep.SemaphoreTokenTargetPreparer">
+ <option name="disable" value="false" />
+ </target_preparer>
+
+ <target_preparer class="com.android.tradefed.targetprep.adb.AdbStopServerPreparer" />
+ <test class="com.android.tradefed.testtype.python.PythonBinaryHostTest" >
+ <option name="par-file-name" value="adb_integration_test_adb" />
+ <option name="inject-android-serial" value="true" />
+ <option name="test-timeout" value="2m" />
+ </test>
+</configuration>
diff --git a/base/Android.bp b/base/Android.bp
index 46a0233..3d80d97 100644
--- a/base/Android.bp
+++ b/base/Android.bp
@@ -135,7 +135,6 @@
"strings_test.cpp",
"test_main.cpp",
"test_utils_test.cpp",
- "unique_fd_test.cpp",
],
target: {
android: {
diff --git a/base/unique_fd_test.cpp b/base/unique_fd_test.cpp
deleted file mode 100644
index 3fdf12a..0000000
--- a/base/unique_fd_test.cpp
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "android-base/unique_fd.h"
-
-#include <gtest/gtest.h>
-
-#include <errno.h>
-#include <fcntl.h>
-#include <unistd.h>
-
-using android::base::unique_fd;
-
-TEST(unique_fd, unowned_close) {
-#if defined(__BIONIC__)
- unique_fd fd(open("/dev/null", O_RDONLY));
- EXPECT_DEATH(close(fd.get()), "incorrect tag");
-#endif
-}
-
-TEST(unique_fd, untag_on_release) {
- unique_fd fd(open("/dev/null", O_RDONLY));
- close(fd.release());
-}
-
-TEST(unique_fd, move) {
- unique_fd fd(open("/dev/null", O_RDONLY));
- unique_fd fd_moved = std::move(fd);
- ASSERT_EQ(-1, fd.get());
- ASSERT_GT(fd_moved.get(), -1);
-}
-
-TEST(unique_fd, unowned_close_after_move) {
-#if defined(__BIONIC__)
- unique_fd fd(open("/dev/null", O_RDONLY));
- unique_fd fd_moved = std::move(fd);
- ASSERT_EQ(-1, fd.get());
- ASSERT_GT(fd_moved.get(), -1);
- EXPECT_DEATH(close(fd_moved.get()), "incorrect tag");
-#endif
-}
diff --git a/fastboot/Android.bp b/fastboot/Android.bp
index 51cc62a..aa88a8a 100644
--- a/fastboot/Android.bp
+++ b/fastboot/Android.bp
@@ -96,6 +96,8 @@
"device/fastboot_device.cpp",
"device/main.cpp",
"device/usb_client.cpp",
+ "device/utility.cpp",
+ "device/variables.cpp",
],
shared_libs: [
@@ -103,6 +105,7 @@
"libext4_utils",
"libsparse",
"liblog",
+ "android.hardware.boot@1.0",
"libbootloader_message",
"libhidltransport",
"libhidlbase",
diff --git a/fastboot/constants.h b/fastboot/constants.h
index 7caca3d..fa17070 100644
--- a/fastboot/constants.h
+++ b/fastboot/constants.h
@@ -51,3 +51,5 @@
#define FB_VAR_HAS_SLOT "has-slot"
#define FB_VAR_SLOT_COUNT "slot-count"
#define FB_VAR_PARTITION_SIZE "partition-size"
+#define FB_VAR_SLOT_SUCCESSFUL "slot-successful"
+#define FB_VAR_SLOT_UNBOOTABLE "slot-unbootable"
diff --git a/fastboot/device/commands.cpp b/fastboot/device/commands.cpp
index a3cbf96..ac381fb 100644
--- a/fastboot/device/commands.cpp
+++ b/fastboot/device/commands.cpp
@@ -27,7 +27,43 @@
#include <android-base/unique_fd.h>
#include <cutils/android_reboot.h>
+#include "constants.h"
#include "fastboot_device.h"
+#include "utility.h"
+
+using ::android::hardware::hidl_string;
+using ::android::hardware::boot::V1_0::BoolResult;
+using ::android::hardware::boot::V1_0::CommandResult;
+using ::android::hardware::boot::V1_0::Slot;
+
+bool GetVarHandler(FastbootDevice* device, const std::vector<std::string>& args) {
+ using VariableHandler =
+ std::function<std::string(FastbootDevice*, const std::vector<std::string>&)>;
+ const std::unordered_map<std::string, VariableHandler> kVariableMap = {
+ {FB_VAR_VERSION, GetVersion},
+ {FB_VAR_VERSION_BOOTLOADER, GetBootloaderVersion},
+ {FB_VAR_VERSION_BASEBAND, GetBasebandVersion},
+ {FB_VAR_PRODUCT, GetProduct},
+ {FB_VAR_SERIALNO, GetSerial},
+ {FB_VAR_SECURE, GetSecure},
+ {FB_VAR_UNLOCKED, GetUnlocked},
+ {FB_VAR_MAX_DOWNLOAD_SIZE, GetMaxDownloadSize},
+ {FB_VAR_CURRENT_SLOT, ::GetCurrentSlot},
+ {FB_VAR_SLOT_COUNT, GetSlotCount},
+ {FB_VAR_HAS_SLOT, GetHasSlot},
+ {FB_VAR_SLOT_SUCCESSFUL, GetSlotSuccessful},
+ {FB_VAR_SLOT_UNBOOTABLE, GetSlotUnbootable}};
+
+ // args[0] is command name, args[1] is variable.
+ auto found_variable = kVariableMap.find(args[1]);
+ if (found_variable == kVariableMap.end()) {
+ return device->WriteStatus(FastbootResult::FAIL, "Unknown variable");
+ }
+
+ std::vector<std::string> getvar_args(args.begin() + 2, args.end());
+ auto result = found_variable->second(device, getvar_args);
+ return device->WriteStatus(FastbootResult::OKAY, result);
+}
bool DownloadHandler(FastbootDevice* device, const std::vector<std::string>& args) {
if (args.size() < 2) {
@@ -51,8 +87,31 @@
return device->WriteStatus(FastbootResult::FAIL, "Couldn't download data");
}
-bool SetActiveHandler(FastbootDevice* device, const std::vector<std::string>& /* args */) {
- return device->WriteStatus(FastbootResult::OKAY, "");
+bool SetActiveHandler(FastbootDevice* device, const std::vector<std::string>& args) {
+ if (args.size() < 2) {
+ return device->WriteStatus(FastbootResult::FAIL, "Missing slot argument");
+ }
+
+ // Slot suffix needs to be between 'a' and 'z'.
+ Slot slot;
+ if (!GetSlotNumber(args[1], &slot)) {
+ return device->WriteStatus(FastbootResult::FAIL, "Bad slot suffix");
+ }
+
+ // Non-A/B devices will not have a boot control HAL.
+ auto boot_control_hal = device->boot_control_hal();
+ if (!boot_control_hal) {
+ return device->WriteStatus(FastbootResult::FAIL,
+ "Cannot set slot: boot control HAL absent");
+ }
+ if (slot >= boot_control_hal->getNumberSlots()) {
+ return device->WriteStatus(FastbootResult::FAIL, "Slot out of range");
+ }
+ CommandResult ret;
+ auto cb = [&ret](CommandResult result) { ret = result; };
+ auto result = boot_control_hal->setActiveBootSlot(slot, cb);
+ if (result.isOk() && ret.success) return device->WriteStatus(FastbootResult::OKAY, "");
+ return device->WriteStatus(FastbootResult::FAIL, "Unable to set slot");
}
bool ShutDownHandler(FastbootDevice* device, const std::vector<std::string>& /* args */) {
diff --git a/fastboot/device/commands.h b/fastboot/device/commands.h
index cd984c8..8785b91 100644
--- a/fastboot/device/commands.h
+++ b/fastboot/device/commands.h
@@ -38,3 +38,4 @@
bool RebootBootloaderHandler(FastbootDevice* device, const std::vector<std::string>& args);
bool RebootFastbootHandler(FastbootDevice* device, const std::vector<std::string>& args);
bool RebootRecoveryHandler(FastbootDevice* device, const std::vector<std::string>& args);
+bool GetVarHandler(FastbootDevice* device, const std::vector<std::string>& args);
diff --git a/fastboot/device/fastboot_device.cpp b/fastboot/device/fastboot_device.cpp
index 4c3d23f..f61e5c2 100644
--- a/fastboot/device/fastboot_device.cpp
+++ b/fastboot/device/fastboot_device.cpp
@@ -18,23 +18,31 @@
#include <android-base/logging.h>
#include <android-base/strings.h>
+#include <android/hardware/boot/1.0/IBootControl.h>
#include <algorithm>
#include "constants.h"
#include "usb_client.h"
+using ::android::hardware::hidl_string;
+using ::android::hardware::boot::V1_0::IBootControl;
+using ::android::hardware::boot::V1_0::Slot;
+namespace sph = std::placeholders;
+
FastbootDevice::FastbootDevice()
: kCommandMap({
{FB_CMD_SET_ACTIVE, SetActiveHandler},
{FB_CMD_DOWNLOAD, DownloadHandler},
+ {FB_CMD_GETVAR, GetVarHandler},
{FB_CMD_SHUTDOWN, ShutDownHandler},
{FB_CMD_REBOOT, RebootHandler},
{FB_CMD_REBOOT_BOOTLOADER, RebootBootloaderHandler},
{FB_CMD_REBOOT_FASTBOOT, RebootFastbootHandler},
{FB_CMD_REBOOT_RECOVERY, RebootRecoveryHandler},
}),
- transport_(std::make_unique<ClientUsbTransport>()) {}
+ transport_(std::make_unique<ClientUsbTransport>()),
+ boot_control_hal_(IBootControl::getService()) {}
FastbootDevice::~FastbootDevice() {
CloseDevice();
@@ -44,9 +52,21 @@
transport_->Close();
}
+std::string FastbootDevice::GetCurrentSlot() {
+ // Non-A/B devices must not have boot control HALs.
+ if (!boot_control_hal_) {
+ return "";
+ }
+ std::string suffix;
+ auto cb = [&suffix](hidl_string s) { suffix = s; };
+ boot_control_hal_->getSuffix(boot_control_hal_->getCurrentSlot(), cb);
+ return suffix;
+}
+
bool FastbootDevice::WriteStatus(FastbootResult result, const std::string& message) {
constexpr size_t kResponseReasonSize = 4;
constexpr size_t kNumResponseTypes = 4; // "FAIL", "OKAY", "INFO", "DATA"
+
char buf[FB_RESPONSE_SZ];
constexpr size_t kMaxMessageSize = sizeof(buf) - kResponseReasonSize;
size_t msg_len = std::min(kMaxMessageSize, message.size());
diff --git a/fastboot/device/fastboot_device.h b/fastboot/device/fastboot_device.h
index fec42a7..1092499 100644
--- a/fastboot/device/fastboot_device.h
+++ b/fastboot/device/fastboot_device.h
@@ -22,10 +22,11 @@
#include <utility>
#include <vector>
+#include <android/hardware/boot/1.0/IBootControl.h>
+
#include "commands.h"
#include "transport.h"
-
-class FastbootDevice;
+#include "variables.h"
class FastbootDevice {
public:
@@ -36,17 +37,21 @@
void ExecuteCommands();
bool WriteStatus(FastbootResult result, const std::string& message);
bool HandleData(bool read, std::vector<char>* data);
+ std::string GetCurrentSlot();
std::vector<char>& get_download_data() { return download_data_; }
void set_upload_data(const std::vector<char>& data) { upload_data_ = data; }
void set_upload_data(std::vector<char>&& data) { upload_data_ = std::move(data); }
Transport* get_transport() { return transport_.get(); }
+ android::sp<android::hardware::boot::V1_0::IBootControl> boot_control_hal() {
+ return boot_control_hal_;
+ }
private:
const std::unordered_map<std::string, CommandHandler> kCommandMap;
std::unique_ptr<Transport> transport_;
-
+ android::sp<android::hardware::boot::V1_0::IBootControl> boot_control_hal_;
std::vector<char> download_data_;
std::vector<char> upload_data_;
};
diff --git a/fastboot/device/utility.cpp b/fastboot/device/utility.cpp
new file mode 100644
index 0000000..c8d2b3e
--- /dev/null
+++ b/fastboot/device/utility.cpp
@@ -0,0 +1,30 @@
+/*
+ * 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 "utility.h"
+
+using android::hardware::boot::V1_0::Slot;
+
+bool GetSlotNumber(const std::string& slot, Slot* number) {
+ if (slot.size() != 1) {
+ return false;
+ }
+ if (slot[0] < 'a' || slot[0] > 'z') {
+ return false;
+ }
+ *number = slot[0] - 'a';
+ return true;
+}
diff --git a/fastboot/device/utility.h b/fastboot/device/utility.h
new file mode 100644
index 0000000..867d693
--- /dev/null
+++ b/fastboot/device/utility.h
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#pragma once
+
+#include <string>
+
+#include <android/hardware/boot/1.0/IBootControl.h>
+
+bool GetSlotNumber(const std::string& slot, android::hardware::boot::V1_0::Slot* number);
diff --git a/fastboot/device/variables.cpp b/fastboot/device/variables.cpp
new file mode 100644
index 0000000..153ab92
--- /dev/null
+++ b/fastboot/device/variables.cpp
@@ -0,0 +1,122 @@
+/*
+ * 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 "variables.h"
+
+#include <android-base/file.h>
+#include <android-base/logging.h>
+#include <android-base/properties.h>
+#include <android-base/stringprintf.h>
+#include <android-base/strings.h>
+#include <ext4_utils/ext4_utils.h>
+
+#include "fastboot_device.h"
+#include "utility.h"
+
+using ::android::hardware::boot::V1_0::BoolResult;
+using ::android::hardware::boot::V1_0::Slot;
+
+constexpr int kMaxDownloadSizeDefault = 0x20000000;
+constexpr char kFastbootProtocolVersion[] = "0.4";
+
+std::string GetVersion(FastbootDevice* /* device */, const std::vector<std::string>& /* args */) {
+ return kFastbootProtocolVersion;
+}
+
+std::string GetBootloaderVersion(FastbootDevice* /* device */,
+ const std::vector<std::string>& /* args */) {
+ return android::base::GetProperty("ro.bootloader", "");
+}
+
+std::string GetBasebandVersion(FastbootDevice* /* device */,
+ const std::vector<std::string>& /* args */) {
+ return android::base::GetProperty("ro.build.expect.baseband", "");
+}
+
+std::string GetProduct(FastbootDevice* /* device */, const std::vector<std::string>& /* args */) {
+ return android::base::GetProperty("ro.product.device", "");
+}
+
+std::string GetSerial(FastbootDevice* /* device */, const std::vector<std::string>& /* args */) {
+ return android::base::GetProperty("ro.serialno", "");
+}
+
+std::string GetSecure(FastbootDevice* /* device */, const std::vector<std::string>& /* args */) {
+ return android::base::GetBoolProperty("ro.secure", "") ? "yes" : "no";
+}
+
+std::string GetCurrentSlot(FastbootDevice* device, const std::vector<std::string>& /* args */) {
+ std::string suffix = device->GetCurrentSlot();
+ return suffix.size() == 2 ? suffix.substr(1) : suffix;
+}
+
+std::string GetSlotCount(FastbootDevice* device, const std::vector<std::string>& /* args */) {
+ auto boot_control_hal = device->boot_control_hal();
+ if (!boot_control_hal) {
+ return "0";
+ }
+ return std::to_string(boot_control_hal->getNumberSlots());
+}
+
+std::string GetSlotSuccessful(FastbootDevice* device, const std::vector<std::string>& args) {
+ if (args.empty()) {
+ return "no";
+ }
+ Slot slot;
+ if (!GetSlotNumber(args[0], &slot)) {
+ return "no";
+ }
+ auto boot_control_hal = device->boot_control_hal();
+ if (!boot_control_hal) {
+ return "no";
+ }
+ return boot_control_hal->isSlotMarkedSuccessful(slot) == BoolResult::TRUE ? "yes" : "no";
+}
+
+std::string GetSlotUnbootable(FastbootDevice* device, const std::vector<std::string>& args) {
+ if (args.empty()) {
+ return "no";
+ }
+ Slot slot;
+ if (!GetSlotNumber(args[0], &slot)) {
+ return "no";
+ }
+ auto boot_control_hal = device->boot_control_hal();
+ if (!boot_control_hal) {
+ return "no";
+ }
+ return boot_control_hal->isSlotBootable(slot) == BoolResult::TRUE ? "no" : "yes";
+}
+
+std::string GetMaxDownloadSize(FastbootDevice* /* device */,
+ const std::vector<std::string>& /* args */) {
+ return std::to_string(kMaxDownloadSizeDefault);
+}
+
+std::string GetUnlocked(FastbootDevice* /* device */, const std::vector<std::string>& /* args */) {
+ return "yes";
+}
+
+std::string GetHasSlot(FastbootDevice* device, const std::vector<std::string>& args) {
+ if (args.empty()) {
+ return "no";
+ }
+ std::string slot_suffix = device->GetCurrentSlot();
+ if (slot_suffix.empty()) {
+ return "no";
+ }
+ return args[0] == "userdata" ? "no" : "yes";
+}
diff --git a/fastboot/device/variables.h b/fastboot/device/variables.h
new file mode 100644
index 0000000..09ef8ec
--- /dev/null
+++ b/fastboot/device/variables.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#pragma once
+
+#include <functional>
+#include <string>
+#include <vector>
+
+class FastbootDevice;
+
+std::string GetVersion(FastbootDevice* device, const std::vector<std::string>& args);
+std::string GetBootloaderVersion(FastbootDevice* device, const std::vector<std::string>& args);
+std::string GetBasebandVersion(FastbootDevice* device, const std::vector<std::string>& args);
+std::string GetProduct(FastbootDevice* device, const std::vector<std::string>& args);
+std::string GetSerial(FastbootDevice* device, const std::vector<std::string>& args);
+std::string GetSecure(FastbootDevice* device, const std::vector<std::string>& args);
+std::string GetCurrentSlot(FastbootDevice* device, const std::vector<std::string>& args);
+std::string GetSlotCount(FastbootDevice* device, const std::vector<std::string>& args);
+std::string GetSlotSuccessful(FastbootDevice* device, const std::vector<std::string>& args);
+std::string GetSlotUnbootable(FastbootDevice* device, const std::vector<std::string>& args);
+std::string GetMaxDownloadSize(FastbootDevice* device, const std::vector<std::string>& args);
+std::string GetUnlocked(FastbootDevice* device, const std::vector<std::string>& args);
+std::string GetHasSlot(FastbootDevice* device, const std::vector<std::string>& args);
diff --git a/libbacktrace/include/backtrace/BacktraceMap.h b/libbacktrace/include/backtrace/BacktraceMap.h
index a9cfce4..c564271 100644
--- a/libbacktrace/include/backtrace/BacktraceMap.h
+++ b/libbacktrace/include/backtrace/BacktraceMap.h
@@ -31,6 +31,7 @@
#include <deque>
#include <iterator>
+#include <memory>
#include <string>
#include <vector>
diff --git a/libunwindstack/include/unwindstack/RegsGetLocal.h b/libunwindstack/include/unwindstack/RegsGetLocal.h
index 81c0af3..f0b5e3a 100644
--- a/libunwindstack/include/unwindstack/RegsGetLocal.h
+++ b/libunwindstack/include/unwindstack/RegsGetLocal.h
@@ -33,8 +33,7 @@
#if defined(__arm__)
-inline __always_inline void RegsGetLocal(Regs* regs) {
- void* reg_data = regs->RawData();
+inline __attribute__((__always_inline__)) void AsmGetRegs(void* reg_data) {
asm volatile(
".align 2\n"
"bx pc\n"
@@ -55,8 +54,7 @@
#elif defined(__aarch64__)
-inline __always_inline void RegsGetLocal(Regs* regs) {
- void* reg_data = regs->RawData();
+inline __attribute__((__always_inline__)) void AsmGetRegs(void* reg_data) {
asm volatile(
"1:\n"
"stp x0, x1, [%[base], #0]\n"
@@ -87,11 +85,12 @@
extern "C" void AsmGetRegs(void* regs);
-inline void RegsGetLocal(Regs* regs) {
+#endif
+
+inline __attribute__((__always_inline__)) void RegsGetLocal(Regs* regs) {
AsmGetRegs(regs->RawData());
}
-#endif
} // namespace unwindstack
diff --git a/libutils/CallStack.cpp b/libutils/CallStack.cpp
index bd6015e..fe6f33d 100644
--- a/libutils/CallStack.cpp
+++ b/libutils/CallStack.cpp
@@ -16,16 +16,15 @@
#define LOG_TAG "CallStack"
-#include <utils/CallStack.h>
-
-#include <memory>
-
#include <utils/Printer.h>
#include <utils/Errors.h>
#include <utils/Log.h>
#include <backtrace/Backtrace.h>
+#define CALLSTACK_WEAK // Don't generate weak definitions.
+#include <utils/CallStack.h>
+
namespace android {
CallStack::CallStack() {
@@ -76,4 +75,30 @@
}
}
+// The following four functions may be used via weak symbol references from libutils.
+// Clients assume that if any of these symbols are available, then deleteStack() is.
+
+#ifdef WEAKS_AVAILABLE
+
+CallStack::CallStackUPtr CallStack::getCurrentInternal(int ignoreDepth) {
+ CallStack::CallStackUPtr stack(new CallStack());
+ stack->update(ignoreDepth + 1);
+ return stack;
+}
+
+void CallStack::logStackInternal(const char* logtag, const CallStack* stack,
+ android_LogPriority priority) {
+ stack->log(logtag, priority);
+}
+
+String8 CallStack::stackToStringInternal(const char* prefix, const CallStack* stack) {
+ return stack->toString(prefix);
+}
+
+void CallStack::deleteStack(CallStack* stack) {
+ delete stack;
+}
+
+#endif // WEAKS_AVAILABLE
+
}; // namespace android
diff --git a/libutils/RefBase.cpp b/libutils/RefBase.cpp
index 9074850..3f1e79a 100644
--- a/libutils/RefBase.cpp
+++ b/libutils/RefBase.cpp
@@ -17,30 +17,41 @@
#define LOG_TAG "RefBase"
// #define LOG_NDEBUG 0
+#include <memory>
+
#include <utils/RefBase.h>
#include <utils/CallStack.h>
+#include <utils/Mutex.h>
+
#ifndef __unused
#define __unused __attribute__((__unused__))
#endif
-// compile with refcounting debugging enabled
-#define DEBUG_REFS 0
+// Compile with refcounting debugging enabled.
+#define DEBUG_REFS 0
+
+// The following three are ignored unless DEBUG_REFS is set.
// whether ref-tracking is enabled by default, if not, trackMe(true, false)
// needs to be called explicitly
-#define DEBUG_REFS_ENABLED_BY_DEFAULT 0
+#define DEBUG_REFS_ENABLED_BY_DEFAULT 0
// whether callstack are collected (significantly slows things down)
-#define DEBUG_REFS_CALLSTACK_ENABLED 1
+#define DEBUG_REFS_CALLSTACK_ENABLED 1
// folder where stack traces are saved when DEBUG_REFS is enabled
// this folder needs to exist and be writable
-#define DEBUG_REFS_CALLSTACK_PATH "/data/debug"
+#define DEBUG_REFS_CALLSTACK_PATH "/data/debug"
// log all reference counting operations
-#define PRINT_REFS 0
+#define PRINT_REFS 0
+
+// Continue after logging a stack trace if ~RefBase discovers that reference
+// count has never been incremented. Normally we conspicuously crash in that
+// case.
+#define DEBUG_REFBASE_DESTRUCTION 1
// ---------------------------------------------------------------------------
@@ -184,7 +195,7 @@
char inc = refs->ref >= 0 ? '+' : '-';
ALOGD("\t%c ID %p (ref %d):", inc, refs->id, refs->ref);
#if DEBUG_REFS_CALLSTACK_ENABLED
- refs->stack.log(LOG_TAG);
+ CallStack::logStack(LOG_TAG, refs->stack.get());
#endif
refs = refs->next;
}
@@ -198,14 +209,14 @@
char inc = refs->ref >= 0 ? '+' : '-';
ALOGD("\t%c ID %p (ref %d):", inc, refs->id, refs->ref);
#if DEBUG_REFS_CALLSTACK_ENABLED
- refs->stack.log(LOG_TAG);
+ CallStack::logStack(LOG_TAG, refs->stack.get());
#endif
refs = refs->next;
}
}
if (dumpStack) {
ALOGE("above errors at:");
- CallStack stack(LOG_TAG);
+ CallStack::logStack(LOG_TAG);
}
}
@@ -279,7 +290,7 @@
this);
int rc = open(name, O_RDWR | O_CREAT | O_APPEND, 644);
if (rc >= 0) {
- write(rc, text.string(), text.length());
+ (void)write(rc, text.string(), text.length());
close(rc);
ALOGD("STACK TRACE for %p saved in %s", this, name);
}
@@ -294,7 +305,7 @@
ref_entry* next;
const void* id;
#if DEBUG_REFS_CALLSTACK_ENABLED
- CallStack stack;
+ CallStack::CallStackUPtr stack;
#endif
int32_t ref;
};
@@ -311,7 +322,7 @@
ref->ref = mRef;
ref->id = id;
#if DEBUG_REFS_CALLSTACK_ENABLED
- ref->stack.update(2);
+ ref->stack = CallStack::getCurrent(2);
#endif
ref->next = *refs;
*refs = ref;
@@ -346,7 +357,7 @@
ref = ref->next;
}
- CallStack stack(LOG_TAG);
+ CallStack::logStack(LOG_TAG);
}
}
@@ -373,7 +384,7 @@
inc, refs->id, refs->ref);
out->append(buf);
#if DEBUG_REFS_CALLSTACK_ENABLED
- out->append(refs->stack.toString("\t\t"));
+ out->append(CallStack::stackToString("\t\t", refs->stack.get()));
#else
out->append("\t\t(call stacks disabled)");
#endif
@@ -700,16 +711,16 @@
if (mRefs->mWeak.load(std::memory_order_relaxed) == 0) {
delete mRefs;
}
- } else if (mRefs->mStrong.load(std::memory_order_relaxed)
- == INITIAL_STRONG_VALUE) {
+ } else if (mRefs->mStrong.load(std::memory_order_relaxed) == INITIAL_STRONG_VALUE) {
// We never acquired a strong reference on this object.
- LOG_ALWAYS_FATAL_IF(mRefs->mWeak.load() != 0,
- "RefBase: Explicit destruction with non-zero weak "
- "reference count");
- // TODO: Always report if we get here. Currently MediaMetadataRetriever
- // C++ objects are inconsistently managed and sometimes get here.
- // There may be other cases, but we believe they should all be fixed.
- delete mRefs;
+#if DEBUG_REFBASE_DESTRUCTION
+ // Treating this as fatal is prone to causing boot loops. For debugging, it's
+ // better to treat as non-fatal.
+ ALOGD("RefBase: Explicit destruction, weak count = %d (in %p)", mRefs->mWeak.load(), this);
+ CallStack::logStack(LOG_TAG);
+#else
+ LOG_ALWAYS_FATAL("RefBase: Explicit destruction, weak count = %d", mRefs->mWeak.load());
+#endif
}
// For debugging purposes, clear mRefs. Ineffective against outstanding wp's.
const_cast<weakref_impl*&>(mRefs) = nullptr;
diff --git a/libutils/include/utils/CallStack.h b/libutils/include/utils/CallStack.h
index 0c1b875..56004fe 100644
--- a/libutils/include/utils/CallStack.h
+++ b/libutils/include/utils/CallStack.h
@@ -17,6 +17,8 @@
#ifndef ANDROID_CALLSTACK_H
#define ANDROID_CALLSTACK_H
+#include <memory>
+
#include <android/log.h>
#include <backtrace/backtrace_constants.h>
#include <utils/String8.h>
@@ -25,6 +27,19 @@
#include <stdint.h>
#include <sys/types.h>
+#if !defined(__APPLE__) && !defined(_WIN32)
+# define WEAKS_AVAILABLE 1
+#endif
+#ifndef CALLSTACK_WEAK
+# ifdef WEAKS_AVAILABLE
+# define CALLSTACK_WEAK __attribute__((weak))
+# else // !WEAKS_AVAILABLE
+# define CALLSTACK_WEAK
+# endif // !WEAKS_AVAILABLE
+#endif // CALLSTACK_WEAK predefined
+
+#define ALWAYS_INLINE __attribute__((always_inline))
+
namespace android {
class Printer;
@@ -36,7 +51,7 @@
CallStack();
// Create a callstack with the current thread's stack trace.
// Immediately dump it to logcat using the given logtag.
- CallStack(const char* logtag, int32_t ignoreDepth=1);
+ CallStack(const char* logtag, int32_t ignoreDepth = 1);
~CallStack();
// Reset the stack frames (same as creating an empty call stack).
@@ -44,7 +59,7 @@
// Immediately collect the stack traces for the specified thread.
// The default is to dump the stack of the current call.
- void update(int32_t ignoreDepth=1, pid_t tid=BACKTRACE_CURRENT_THREAD);
+ void update(int32_t ignoreDepth = 1, pid_t tid = BACKTRACE_CURRENT_THREAD);
// Dump a stack trace to the log using the supplied logtag.
void log(const char* logtag,
@@ -63,7 +78,88 @@
// Get the count of stack frames that are in this call stack.
size_t size() const { return mFrameLines.size(); }
-private:
+ // DO NOT USE ANYTHING BELOW HERE. The following public members are expected
+ // to disappear again shortly, once a better replacement facility exists.
+ // The replacement facility will be incompatible!
+
+ // Debugging accesses to some basic functionality. These use weak symbols to
+ // avoid introducing a dependency on libutilscallstack. Such a dependency from
+ // libutils results in a cyclic build dependency. These routines can be called
+ // from within libutils. But if the actual library is unavailable, they do
+ // nothing.
+ //
+ // DO NOT USE THESE. They will disappear.
+ struct StackDeleter {
+#ifdef WEAKS_AVAILABLE
+ void operator()(CallStack* stack) {
+ deleteStack(stack);
+ }
+#else
+ void operator()(CallStack*) {}
+#endif
+ };
+
+ typedef std::unique_ptr<CallStack, StackDeleter> CallStackUPtr;
+
+ // Return current call stack if possible, nullptr otherwise.
+#ifdef WEAKS_AVAILABLE
+ static CallStackUPtr ALWAYS_INLINE getCurrent(int32_t ignoreDepth = 1) {
+ if (reinterpret_cast<uintptr_t>(getCurrentInternal) == 0) {
+ ALOGW("CallStack::getCurrentInternal not linked, returning null");
+ return CallStackUPtr(nullptr);
+ } else {
+ return getCurrentInternal(ignoreDepth);
+ }
+ }
+#else // !WEAKS_AVAILABLE
+ static CallStackUPtr ALWAYS_INLINE getCurrent(int32_t = 1) {
+ return CallStackUPtr(nullptr);
+ }
+#endif // !WEAKS_AVAILABLE
+
+#ifdef WEAKS_AVAILABLE
+ static void ALWAYS_INLINE logStack(const char* logtag, CallStack* stack = getCurrent().get(),
+ android_LogPriority priority = ANDROID_LOG_DEBUG) {
+ if (reinterpret_cast<uintptr_t>(logStackInternal) != 0 && stack != nullptr) {
+ logStackInternal(logtag, stack, priority);
+ } else {
+ ALOGW("CallStack::logStackInternal not linked");
+ }
+ }
+
+#else
+ static void ALWAYS_INLINE logStack(const char*, CallStack* = getCurrent().get(),
+ android_LogPriority = ANDROID_LOG_DEBUG) {
+ }
+#endif // !WEAKS_AVAILABLE
+
+#ifdef WEAKS_AVAILABLE
+ static String8 ALWAYS_INLINE stackToString(const char* prefix = nullptr,
+ const CallStack* stack = getCurrent().get()) {
+ if (reinterpret_cast<uintptr_t>(stackToStringInternal) != 0 && stack != nullptr) {
+ return stackToStringInternal(prefix, stack);
+ } else {
+ return String8("<CallStack package not linked>");
+ }
+ }
+#else // !WEAKS_AVAILABLE
+ static String8 ALWAYS_INLINE stackToString(const char* = nullptr,
+ const CallStack* = getCurrent().get()) {
+ return String8("<CallStack package not linked>");
+ }
+#endif // !WEAKS_AVAILABLE
+
+ private:
+#ifdef WEAKS_AVAILABLE
+ static CallStackUPtr CALLSTACK_WEAK getCurrentInternal(int32_t ignoreDepth);
+ static void CALLSTACK_WEAK logStackInternal(const char* logtag, const CallStack* stack,
+ android_LogPriority priority);
+ static String8 CALLSTACK_WEAK stackToStringInternal(const char* prefix, const CallStack* stack);
+ // The deleter is only invoked on non-null pointers. Hence it will never be
+ // invoked if CallStack is not linked.
+ static void CALLSTACK_WEAK deleteStack(CallStack* stack);
+#endif // WEAKS_AVAILABLE
+
Vector<String8> mFrameLines;
};