Merge "Preserve x18 while calling aptX encoder libraries."
diff --git a/common/scoped_scs_exit.h b/common/scoped_scs_exit.h
new file mode 100644
index 0000000..ad4a8d6
--- /dev/null
+++ b/common/scoped_scs_exit.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright 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
+
+// Prevent x18 (shadow call stack address) from being clobbered by functions
+// called by a function that declares a variable of this type by temporarily
+// storing the value on the stack. This is used only when calling out to certain
+// vendor libraries.
+struct ScopedSCSExit {
+#ifdef __aarch64__
+    void* scs;
+
+    __attribute__((always_inline, no_sanitize("shadow-call-stack"))) ScopedSCSExit() {
+        __asm__ __volatile__("str x18, [%0]" ::"r"(&scs));
+    }
+
+    __attribute__((always_inline, no_sanitize("shadow-call-stack"))) ~ScopedSCSExit() {
+        __asm__ __volatile__("ldr x18, [%0]; str xzr, [%0]" ::"r"(&scs));
+    }
+#else
+    // Silence unused variable warnings in non-SCS builds.
+    __attribute__((no_sanitize("shadow-call-stack"))) ScopedSCSExit() {}
+    __attribute__((no_sanitize("shadow-call-stack"))) ~ScopedSCSExit() {}
+#endif
+};
diff --git a/stack/a2dp/a2dp_vendor_aptx_encoder.cc b/stack/a2dp/a2dp_vendor_aptx_encoder.cc
index 0d605c0..e7d0145 100644
--- a/stack/a2dp/a2dp_vendor_aptx_encoder.cc
+++ b/stack/a2dp/a2dp_vendor_aptx_encoder.cc
@@ -26,6 +26,7 @@
 #include "a2dp_vendor.h"
 #include "a2dp_vendor_aptx.h"
 #include "bt_common.h"
+#include "common/scoped_scs_exit.h"
 #include "common/time_util.h"
 #include "osi/include/log.h"
 #include "osi/include/osi.h"
@@ -54,6 +55,25 @@
 static tAPTX_ENCODER_ENCODE_STEREO aptx_encoder_encode_stereo_func;
 static tAPTX_ENCODER_SIZEOF_PARAMS aptx_encoder_sizeof_params_func;
 
+__attribute__((no_sanitize("shadow-call-stack")))
+static int aptx_encoder_init(void* state, short endian) {
+  ScopedSCSExit x;
+  return aptx_encoder_init_func(state, endian);
+}
+
+__attribute__((no_sanitize("shadow-call-stack")))
+static int aptx_encoder_encode_stereo(void* state, void* pcmL, void* pcmR,
+                                      void* buffer) {
+  ScopedSCSExit x;
+  return aptx_encoder_encode_stereo_func(state, pcmL, pcmR, buffer);
+}
+
+__attribute__((no_sanitize("shadow-call-stack")))
+static int aptx_encoder_sizeof_params() {
+  ScopedSCSExit x;
+  return aptx_encoder_sizeof_params_func();
+}
+
 // offset
 #if (BTA_AV_CO_CP_SCMS_T == TRUE)
 #define A2DP_APTX_OFFSET (AVDT_MEDIA_OFFSET + 1)
@@ -192,9 +212,9 @@
 #endif
 
   a2dp_aptx_encoder_cb.aptx_encoder_state =
-      osi_malloc(aptx_encoder_sizeof_params_func());
+      osi_malloc(aptx_encoder_sizeof_params());
   if (a2dp_aptx_encoder_cb.aptx_encoder_state != NULL) {
-    aptx_encoder_init_func(a2dp_aptx_encoder_cb.aptx_encoder_state, 0);
+    aptx_encoder_init(a2dp_aptx_encoder_cb.aptx_encoder_state, 0);
   } else {
     LOG_ERROR(LOG_TAG, "%s: Cannot allocate aptX encoder state", __func__);
     // TODO: Return an error?
@@ -466,8 +486,8 @@
       pcmR[i] = (uint16_t) * (data16_in + ((2 * j) + 1));
     }
 
-    aptx_encoder_encode_stereo_func(a2dp_aptx_encoder_cb.aptx_encoder_state,
-                                    &pcmL, &pcmR, &encoded_sample);
+    aptx_encoder_encode_stereo(a2dp_aptx_encoder_cb.aptx_encoder_state, &pcmL,
+                               &pcmR, &encoded_sample);
 
     data_out[*data_out_index + 0] = (uint8_t)((encoded_sample[0] >> 8) & 0xff);
     data_out[*data_out_index + 1] = (uint8_t)((encoded_sample[0] >> 0) & 0xff);
diff --git a/stack/a2dp/a2dp_vendor_aptx_hd_encoder.cc b/stack/a2dp/a2dp_vendor_aptx_hd_encoder.cc
index fb782dd..d271e0d 100644
--- a/stack/a2dp/a2dp_vendor_aptx_hd_encoder.cc
+++ b/stack/a2dp/a2dp_vendor_aptx_hd_encoder.cc
@@ -26,6 +26,7 @@
 #include "a2dp_vendor.h"
 #include "a2dp_vendor_aptx_hd.h"
 #include "bt_common.h"
+#include "common/scoped_scs_exit.h"
 #include "common/time_util.h"
 #include "osi/include/log.h"
 #include "osi/include/osi.h"
@@ -55,6 +56,25 @@
 static tAPTX_HD_ENCODER_ENCODE_STEREO aptx_hd_encoder_encode_stereo_func;
 static tAPTX_HD_ENCODER_SIZEOF_PARAMS aptx_hd_encoder_sizeof_params_func;
 
+__attribute__((no_sanitize("shadow-call-stack")))
+static int aptx_hd_encoder_init(void* state, short endian) {
+  ScopedSCSExit x;
+  return aptx_hd_encoder_init_func(state, endian);
+}
+
+__attribute__((no_sanitize("shadow-call-stack")))
+static int aptx_hd_encoder_encode_stereo(void* state, void* pcmL, void* pcmR,
+                                         void* buffer) {
+  ScopedSCSExit x;
+  return aptx_hd_encoder_encode_stereo_func(state, pcmL, pcmR, buffer);
+}
+
+__attribute__((no_sanitize("shadow-call-stack")))
+static int aptx_hd_encoder_sizeof_params() {
+  ScopedSCSExit x;
+  return aptx_hd_encoder_sizeof_params_func();
+}
+
 // offset
 #if (BTA_AV_CO_CP_SCMS_T == TRUE)
 #define A2DP_APTX_HD_OFFSET (AVDT_MEDIA_OFFSET + 1)
@@ -193,9 +213,9 @@
 #endif
 
   a2dp_aptx_hd_encoder_cb.aptx_hd_encoder_state =
-      osi_malloc(aptx_hd_encoder_sizeof_params_func());
+      osi_malloc(aptx_hd_encoder_sizeof_params());
   if (a2dp_aptx_hd_encoder_cb.aptx_hd_encoder_state != NULL) {
-    aptx_hd_encoder_init_func(a2dp_aptx_hd_encoder_cb.aptx_hd_encoder_state, 0);
+    aptx_hd_encoder_init(a2dp_aptx_hd_encoder_cb.aptx_hd_encoder_state, 0);
   } else {
     LOG_ERROR(LOG_TAG, "%s: Cannot allocate aptX-HD encoder state", __func__);
     // TODO: Return an error?
@@ -460,7 +480,7 @@
       p += 3;
     }
 
-    aptx_hd_encoder_encode_stereo_func(
+    aptx_hd_encoder_encode_stereo(
         a2dp_aptx_hd_encoder_cb.aptx_hd_encoder_state, &pcmL, &pcmR,
         &encoded_sample);