Merge "Support IMPLEMENT_META_INTERFACE for nested type"
diff --git a/libs/binder/Parcel.cpp b/libs/binder/Parcel.cpp
index 631a4b6..8f4f0f0 100644
--- a/libs/binder/Parcel.cpp
+++ b/libs/binder/Parcel.cpp
@@ -521,6 +521,25 @@
     return memcmp(data(), other.data(), size);
 }
 
+status_t Parcel::compareDataInRange(size_t thisOffset, const Parcel& other, size_t otherOffset,
+                                    size_t len, int* result) const {
+    if (len > INT32_MAX || thisOffset > INT32_MAX || otherOffset > INT32_MAX) {
+        // Don't accept size_t values which may have come from an inadvertent conversion from a
+        // negative int.
+        return BAD_VALUE;
+    }
+    size_t thisLimit;
+    if (__builtin_add_overflow(thisOffset, len, &thisLimit) || thisLimit > mDataSize) {
+        return BAD_VALUE;
+    }
+    size_t otherLimit;
+    if (__builtin_add_overflow(otherOffset, len, &otherLimit) || otherLimit > other.mDataSize) {
+        return BAD_VALUE;
+    }
+    *result = memcmp(data() + thisOffset, other.data() + otherOffset, len);
+    return NO_ERROR;
+}
+
 bool Parcel::allowFds() const
 {
     return mAllowFds;
diff --git a/libs/binder/include/binder/Parcel.h b/libs/binder/include/binder/Parcel.h
index d90e803..8fb4a37 100644
--- a/libs/binder/include/binder/Parcel.h
+++ b/libs/binder/include/binder/Parcel.h
@@ -81,6 +81,8 @@
                                    size_t start, size_t len);
 
     int                 compareData(const Parcel& other);
+    status_t compareDataInRange(size_t thisOffset, const Parcel& other, size_t otherOffset,
+                                size_t length, int* result) const;
 
     bool                allowFds() const;
     bool                pushAllowFds(bool allowFds);
diff --git a/libs/binder/ndk/ibinder.cpp b/libs/binder/ndk/ibinder.cpp
index 81aa551..8ffa735 100644
--- a/libs/binder/ndk/ibinder.cpp
+++ b/libs/binder/ndk/ibinder.cpp
@@ -555,6 +555,10 @@
     return ::android::IPCThreadState::self()->getCallingPid();
 }
 
+bool AIBinder_isHandlingTransaction() {
+    return ::android::IPCThreadState::self()->getServingStackPointer() != nullptr;
+}
+
 void AIBinder_incStrong(AIBinder* binder) {
     if (binder == nullptr) {
         return;
diff --git a/libs/binder/ndk/include_ndk/android/binder_ibinder.h b/libs/binder/ndk/include_ndk/android/binder_ibinder.h
index 43533c5..565542b 100644
--- a/libs/binder/ndk/include_ndk/android/binder_ibinder.h
+++ b/libs/binder/ndk/include_ndk/android/binder_ibinder.h
@@ -393,6 +393,14 @@
 pid_t AIBinder_getCallingPid() __INTRODUCED_IN(29);
 
 /**
+ * Determine whether the current thread is currently executing an incoming transaction.
+ *
+ * \return true if the current thread is currently executing an incoming transaction, and false
+ * otherwise.
+ */
+bool AIBinder_isHandlingTransaction() __INTRODUCED_IN(33);
+
+/**
  * This can only be called if a strong reference to this object already exists in process.
  *
  * Available since API level 29.
diff --git a/libs/binder/ndk/libbinder_ndk.map.txt b/libs/binder/ndk/libbinder_ndk.map.txt
index 64170af..d63a8d0 100644
--- a/libs/binder/ndk/libbinder_ndk.map.txt
+++ b/libs/binder/ndk/libbinder_ndk.map.txt
@@ -145,6 +145,7 @@
   global:
     AIBinder_Class_disableInterfaceTokenHeader;
     AIBinder_DeathRecipient_setOnUnlinked;
+    AIBinder_isHandlingTransaction;
     AIBinder_setMinSchedulerPolicy; # llndk
     AParcel_marshal;
     AParcel_unmarshal;
diff --git a/libs/binder/rust/src/state.rs b/libs/binder/rust/src/state.rs
index 0e05f10..0aef744 100644
--- a/libs/binder/rust/src/state.rs
+++ b/libs/binder/rust/src/state.rs
@@ -99,6 +99,17 @@
         }
     }
 
+    /// Determine whether the current thread is currently executing an incoming transaction.
+    ///
+    /// \return true if the current thread is currently executing an incoming transaction, and false
+    /// otherwise.
+    pub fn is_handling_transaction() -> bool {
+        unsafe {
+            // Safety: Safe FFI
+            sys::AIBinder_isHandlingTransaction()
+        }
+    }
+
     /// This function makes the client's security context available to the
     /// service calling this function. This can be used for access control.
     /// It does not suffer from the TOCTOU issues of get_calling_pid.
diff --git a/libs/binder/tests/parcel_fuzzer/binder.cpp b/libs/binder/tests/parcel_fuzzer/binder.cpp
index e4f57b0..155a25b 100644
--- a/libs/binder/tests/parcel_fuzzer/binder.cpp
+++ b/libs/binder/tests/parcel_fuzzer/binder.cpp
@@ -308,6 +308,15 @@
         status_t status = p.hasFileDescriptorsInRange(offset, length, &result);
         FUZZ_LOG() << " status: " << status  << " result: " << result;
     },
+    [] (const ::android::Parcel& p, uint8_t /* data */) {
+        FUZZ_LOG() << "about to call compareDataInRange() with status";
+        size_t thisOffset = p.readUint32();
+        size_t otherOffset = p.readUint32();
+        size_t length = p.readUint32();
+        int result;
+        status_t status = p.compareDataInRange(thisOffset, p, otherOffset, length, &result);
+        FUZZ_LOG() << " status: " << status  << " result: " << result;
+    },
 };
 // clang-format on
 #pragma clang diagnostic pop