Merge "ParseDouble: allow validation only."
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/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