libutils: split out libutils_binder
Dependencies of libbinder, so we can build
a core libbinder library, libbinder_sdk.
This is preparing the way to move this part of libbinder
together with binder code into a single project.
Bug: 302720583
Change-Id: Icff078ac6e36c7f2b91cf815d5b9ed19b2e706e1
diff --git a/libutils/binder/Android.bp b/libutils/binder/Android.bp
new file mode 100644
index 0000000..e2eddb3
--- /dev/null
+++ b/libutils/binder/Android.bp
@@ -0,0 +1,126 @@
+package {
+ default_applicable_licenses: ["system_core_libutils_license"],
+}
+
+cc_defaults {
+ name: "libutils_binder_impl_defaults",
+ defaults: [
+ "libutils_defaults",
+ "apex-lowest-min-sdk-version",
+ ],
+ native_bridge_supported: true,
+
+ srcs: [
+ "Errors.cpp",
+ "RefBase.cpp",
+ "SharedBuffer.cpp",
+ "String16.cpp",
+ "String8.cpp",
+ "StrongPointer.cpp",
+ "Unicode.cpp",
+ "VectorImpl.cpp",
+ ],
+
+ apex_available: [
+ "//apex_available:anyapex",
+ "//apex_available:platform",
+ ],
+
+ afdo: true,
+}
+
+cc_library {
+ name: "libutils_binder",
+ defaults: ["libutils_binder_impl_defaults"],
+}
+
+cc_library {
+ name: "libutils_binder_test_compile",
+ defaults: ["libutils_binder_impl_defaults"],
+
+ cflags: [
+ "-DDEBUG_REFS=1",
+ ],
+
+ visibility: [":__subpackages__"],
+}
+
+cc_fuzz {
+ name: "libutils_fuzz_string8",
+ defaults: ["libutils_fuzz_defaults"],
+ srcs: ["String8_fuzz.cpp"],
+}
+
+cc_fuzz {
+ name: "libutils_fuzz_string16",
+ defaults: ["libutils_fuzz_defaults"],
+ srcs: ["String16_fuzz.cpp"],
+}
+
+cc_fuzz {
+ name: "libutils_fuzz_vector",
+ defaults: ["libutils_fuzz_defaults"],
+ srcs: ["Vector_fuzz.cpp"],
+}
+
+cc_fuzz {
+ name: "libutils_fuzz_refbase",
+ defaults: ["libutils_fuzz_defaults"],
+ srcs: ["RefBase_fuzz.cpp"],
+}
+
+cc_test {
+ name: "libutils_binder_test",
+ host_supported: true,
+
+ srcs: [
+ "Errors_test.cpp",
+ "SharedBuffer_test.cpp",
+ "String16_test.cpp",
+ "String8_test.cpp",
+ "StrongPointer_test.cpp",
+ "Unicode_test.cpp",
+ "Vector_test.cpp",
+ ],
+
+ target: {
+ android: {
+ shared_libs: [
+ "libbase",
+ "libcutils",
+ "liblog",
+ "liblzma",
+ "libutils", // which includes libutils_binder
+ "libz",
+ ],
+ },
+ linux: {
+ srcs: [
+ "RefBase_test.cpp",
+ ],
+ },
+ host: {
+ static_libs: [
+ "libbase",
+ "liblog",
+ "liblzma",
+ "libutils", // which includes libutils_binder
+ ],
+ },
+ },
+
+ cflags: [
+ "-Wall",
+ "-Wextra",
+ "-Werror",
+ "-Wthread-safety",
+ ],
+
+ test_suites: ["device-tests"],
+}
+
+cc_benchmark {
+ name: "libutils_binder_benchmark",
+ srcs: ["Vector_benchmark.cpp"],
+ shared_libs: ["libutils"],
+}
diff --git a/libutils/binder/Errors.cpp b/libutils/binder/Errors.cpp
new file mode 100644
index 0000000..dfb4d9b
--- /dev/null
+++ b/libutils/binder/Errors.cpp
@@ -0,0 +1,53 @@
+/*
+ * 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 <utils/Errors.h>
+
+#include <string.h>
+
+namespace android {
+
+std::string statusToString(status_t s) {
+#define STATUS_CASE(STATUS) \
+ case STATUS: \
+ return #STATUS
+
+ switch (s) {
+ STATUS_CASE(OK);
+ STATUS_CASE(UNKNOWN_ERROR);
+ STATUS_CASE(NO_MEMORY);
+ STATUS_CASE(INVALID_OPERATION);
+ STATUS_CASE(BAD_VALUE);
+ STATUS_CASE(BAD_TYPE);
+ STATUS_CASE(NAME_NOT_FOUND);
+ STATUS_CASE(PERMISSION_DENIED);
+ STATUS_CASE(NO_INIT);
+ STATUS_CASE(ALREADY_EXISTS);
+ STATUS_CASE(DEAD_OBJECT);
+ STATUS_CASE(FAILED_TRANSACTION);
+ STATUS_CASE(BAD_INDEX);
+ STATUS_CASE(NOT_ENOUGH_DATA);
+ STATUS_CASE(WOULD_BLOCK);
+ STATUS_CASE(TIMED_OUT);
+ STATUS_CASE(UNKNOWN_TRANSACTION);
+ STATUS_CASE(FDS_NOT_ALLOWED);
+ STATUS_CASE(UNEXPECTED_NULL);
+#undef STATUS_CASE
+ }
+
+ return std::to_string(s) + " (" + strerror(-s) + ")";
+}
+
+} // namespace android
diff --git a/libutils/binder/Errors_test.cpp b/libutils/binder/Errors_test.cpp
new file mode 100644
index 0000000..0d13bb0
--- /dev/null
+++ b/libutils/binder/Errors_test.cpp
@@ -0,0 +1,172 @@
+/*
+ * Copyright (C) 2021 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 "utils/ErrorsMacros.h"
+
+#include <android-base/result.h>
+
+#include <gtest/gtest.h>
+
+using namespace android;
+
+using android::base::Error;
+using android::base::Result;
+
+status_t success_or_fail(bool success) {
+ if (success)
+ return OK;
+ else
+ return PERMISSION_DENIED;
+}
+
+TEST(errors, unwrap_or_return) {
+ auto f = [](bool success, int* val) -> status_t {
+ OR_RETURN(success_or_fail(success));
+ *val = 10;
+ return OK;
+ };
+
+ int val;
+ status_t s = f(true, &val);
+ EXPECT_EQ(OK, s);
+ EXPECT_EQ(10, val);
+
+ val = 0; // reset
+ status_t q = f(false, &val);
+ EXPECT_EQ(PERMISSION_DENIED, q);
+ EXPECT_EQ(0, val);
+}
+
+TEST(errors, unwrap_or_return_result) {
+ auto f = [](bool success) -> Result<std::string, StatusT> {
+ OR_RETURN(success_or_fail(success));
+ return "hello";
+ };
+
+ auto r = f(true);
+ EXPECT_TRUE(r.ok());
+ EXPECT_EQ("hello", *r);
+
+ auto s = f(false);
+ EXPECT_FALSE(s.ok());
+ EXPECT_EQ(PERMISSION_DENIED, s.error().code());
+ EXPECT_EQ("PERMISSION_DENIED", s.error().message());
+}
+
+TEST(errors, unwrap_or_return_result_int) {
+ auto f = [](bool success) -> Result<int, StatusT> {
+ OR_RETURN(success_or_fail(success));
+ return 10;
+ };
+
+ auto r = f(true);
+ EXPECT_TRUE(r.ok());
+ EXPECT_EQ(10, *r);
+
+ auto s = f(false);
+ EXPECT_FALSE(s.ok());
+ EXPECT_EQ(PERMISSION_DENIED, s.error().code());
+ EXPECT_EQ("PERMISSION_DENIED", s.error().message());
+}
+
+TEST(errors, unwrap_or_fatal) {
+ OR_FATAL(success_or_fail(true));
+
+ EXPECT_DEATH(OR_FATAL(success_or_fail(false)), "PERMISSION_DENIED");
+}
+
+TEST(errors, result_in_status) {
+ auto f = [](bool success) -> Result<std::string, StatusT> {
+ if (success)
+ return "OK";
+ else
+ return Error<StatusT>(PERMISSION_DENIED) << "custom error message";
+ };
+
+ auto g = [&](bool success) -> status_t {
+ std::string val = OR_RETURN(f(success));
+ EXPECT_EQ("OK", val);
+ return OK;
+ };
+
+ status_t a = g(true);
+ EXPECT_EQ(OK, a);
+
+ status_t b = g(false);
+ EXPECT_EQ(PERMISSION_DENIED, b);
+}
+
+TEST(errors, conversion_promotion) {
+ constexpr size_t successVal = 10ull;
+ auto f = [&](bool success) -> Result<size_t, StatusT> {
+ OR_RETURN(success_or_fail(success));
+ return successVal;
+ };
+ auto s = f(true);
+ ASSERT_TRUE(s.ok());
+ EXPECT_EQ(s.value(), successVal);
+ auto r = f(false);
+ EXPECT_TRUE(!r.ok());
+ EXPECT_EQ(PERMISSION_DENIED, r.error().code());
+}
+
+TEST(errors, conversion_promotion_bool) {
+ constexpr size_t successVal = true;
+ auto f = [&](bool success) -> Result<bool, StatusT> {
+ OR_RETURN(success_or_fail(success));
+ return successVal;
+ };
+ auto s = f(true);
+ ASSERT_TRUE(s.ok());
+ EXPECT_EQ(s.value(), successVal);
+ auto r = f(false);
+ EXPECT_TRUE(!r.ok());
+ EXPECT_EQ(PERMISSION_DENIED, r.error().code());
+}
+
+TEST(errors, conversion_promotion_char) {
+ constexpr char successVal = 'a';
+ auto f = [&](bool success) -> Result<unsigned char, StatusT> {
+ OR_RETURN(success_or_fail(success));
+ return successVal;
+ };
+ auto s = f(true);
+ ASSERT_TRUE(s.ok());
+ EXPECT_EQ(s.value(), successVal);
+ auto r = f(false);
+ EXPECT_TRUE(!r.ok());
+ EXPECT_EQ(PERMISSION_DENIED, r.error().code());
+}
+
+struct IntContainer {
+ // Implicit conversion from int is desired
+ IntContainer(int val) : val_(val) {}
+ int val_;
+};
+
+TEST(errors, conversion_construct) {
+ constexpr int successVal = 10;
+ auto f = [&](bool success) -> Result<IntContainer, StatusT> {
+ OR_RETURN(success_or_fail(success));
+ return successVal;
+ };
+ auto s = f(true);
+ ASSERT_TRUE(s.ok());
+ EXPECT_EQ(s.value().val_, successVal);
+ auto r = f(false);
+ EXPECT_TRUE(!r.ok());
+ EXPECT_EQ(PERMISSION_DENIED, r.error().code());
+}
diff --git a/libutils/binder/FuzzFormatTypes.h b/libutils/binder/FuzzFormatTypes.h
new file mode 100644
index 0000000..aa9e503
--- /dev/null
+++ b/libutils/binder/FuzzFormatTypes.h
@@ -0,0 +1,61 @@
+/*
+ * Copyright 2020 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>
+
+static const std::string kFormatChars = std::string("duoxXfFeEgGaAcsp");
+static constexpr int32_t kMaxFormatFlagValue = INT16_MAX;
+enum FormatChar : uint8_t {
+ SIGNED_DECIMAL = 0,
+ UNSIGNED_DECIMAL = 1,
+ UNSIGNED_OCTAL = 2,
+ UNSIGNED_HEX_LOWER = 3,
+ UNSIGNED_HEX_UPPER = 4,
+ // Uppercase/lowercase floating point impacts 'inf', 'infinity', and 'nan'
+ FLOAT_LOWER = 5,
+ FLOAT_UPPER = 6,
+ // Upper/lower impacts the "e" in exponents.
+ EXPONENT_LOWER = 7,
+ EXPONENT_UPPER = 8,
+ // %g will use %e or %f, whichever is shortest
+ SHORT_EXP_LOWER = 9,
+ // %G will use %E or %F, whichever is shortest
+ SHORT_EXP_UPPER = 10,
+ HEX_FLOAT_LOWER = 11,
+ HEX_FLOAT_UPPER = 12,
+ CHAR = 13,
+ STRING = 14,
+ POINTER = 15,
+ // Used by libfuzzer
+ kMaxValue = POINTER
+};
+
+bool canApplyFlag(FormatChar formatChar, char modifier) {
+ if (modifier == '#') {
+ return formatChar == UNSIGNED_OCTAL || formatChar == UNSIGNED_HEX_LOWER ||
+ formatChar == UNSIGNED_HEX_UPPER || formatChar == FLOAT_LOWER ||
+ formatChar == FLOAT_UPPER || formatChar == SHORT_EXP_LOWER ||
+ formatChar == SHORT_EXP_UPPER;
+ } else if (modifier == '.') {
+ return formatChar == SIGNED_DECIMAL || formatChar == UNSIGNED_DECIMAL ||
+ formatChar == UNSIGNED_OCTAL || formatChar == UNSIGNED_HEX_LOWER ||
+ formatChar == UNSIGNED_HEX_UPPER || formatChar == FLOAT_LOWER ||
+ formatChar == FLOAT_UPPER || formatChar == SHORT_EXP_LOWER ||
+ formatChar == SHORT_EXP_UPPER || formatChar == STRING;
+ }
+ return true;
+}
diff --git a/libutils/binder/RefBase.cpp b/libutils/binder/RefBase.cpp
new file mode 100644
index 0000000..c7055fb
--- /dev/null
+++ b/libutils/binder/RefBase.cpp
@@ -0,0 +1,856 @@
+/*
+ * Copyright (C) 2005 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.
+ */
+
+#define LOG_TAG "RefBase"
+// #define LOG_NDEBUG 0
+
+#include <memory>
+#include <mutex>
+
+#include <android-base/macros.h>
+
+#include <fcntl.h>
+#include <log/log.h>
+
+#include <utils/RefBase.h>
+#include <utils/String8.h>
+
+#ifndef __unused
+#define __unused __attribute__((__unused__))
+#endif
+
+// Compile with refcounting debugging enabled.
+#ifndef DEBUG_REFS
+#define DEBUG_REFS 0
+#endif
+
+// 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
+
+// whether callstack are collected (significantly slows things down)
+#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
+#ifdef __ANDROID__
+#define DEBUG_REFS_CALLSTACK_PATH "/data/debug"
+#else
+#define DEBUG_REFS_CALLSTACK_PATH "."
+#endif
+
+// log all reference counting operations
+#define PRINT_REFS 0
+
+#if defined(__linux__)
+// CallStack is only supported on linux type platforms.
+#define CALLSTACK_ENABLED 1
+#else
+#define CALLSTACK_ENABLED 0
+#endif
+
+#if CALLSTACK_ENABLED
+#include <utils/CallStack.h>
+#endif
+
+// ---------------------------------------------------------------------------
+
+namespace android {
+
+// Observations, invariants, etc:
+
+// By default, obects are destroyed when the last strong reference disappears
+// or, if the object never had a strong reference, when the last weak reference
+// disappears.
+//
+// OBJECT_LIFETIME_WEAK changes this behavior to retain the object
+// unconditionally until the last reference of either kind disappears. The
+// client ensures that the extendObjectLifetime call happens before the dec
+// call that would otherwise have deallocated the object, or before an
+// attemptIncStrong call that might rely on it. We do not worry about
+// concurrent changes to the object lifetime.
+//
+// AttemptIncStrong will succeed if the object has a strong reference, or if it
+// has a weak reference and has never had a strong reference.
+// AttemptIncWeak really does succeed only if there is already a WEAK
+// reference, and thus may fail when attemptIncStrong would succeed.
+//
+// mStrong is the strong reference count. mWeak is the weak reference count.
+// Between calls, and ignoring memory ordering effects, mWeak includes strong
+// references, and is thus >= mStrong.
+//
+// A weakref_impl holds all the information, including both reference counts,
+// required to perform wp<> operations. Thus these can continue to be performed
+// after the RefBase object has been destroyed.
+//
+// A weakref_impl is allocated as the value of mRefs in a RefBase object on
+// construction.
+// In the OBJECT_LIFETIME_STRONG case, it is normally deallocated in decWeak,
+// and hence lives as long as the last weak reference. (It can also be
+// deallocated in the RefBase destructor iff the strong reference count was
+// never incremented and the weak count is zero, e.g. if the RefBase object is
+// explicitly destroyed without decrementing the strong count. This should be
+// avoided.) In this case, the RefBase destructor should be invoked from
+// decStrong.
+// In the OBJECT_LIFETIME_WEAK case, the weakref_impl is always deallocated in
+// the RefBase destructor, which is always invoked by decWeak. DecStrong
+// explicitly avoids the deletion in this case.
+//
+// Memory ordering:
+// The client must ensure that every inc() call, together with all other
+// accesses to the object, happens before the corresponding dec() call.
+//
+// We try to keep memory ordering constraints on atomics as weak as possible,
+// since memory fences or ordered memory accesses are likely to be a major
+// performance cost for this code. All accesses to mStrong, mWeak, and mFlags
+// explicitly relax memory ordering in some way.
+//
+// The only operations that are not memory_order_relaxed are reference count
+// decrements. All reference count decrements are release operations. In
+// addition, the final decrement leading the deallocation is followed by an
+// acquire fence, which we can view informally as also turning it into an
+// acquire operation. (See 29.8p4 [atomics.fences] for details. We could
+// alternatively use acq_rel operations for all decrements. This is probably
+// slower on most current (2016) hardware, especially on ARMv7, but that may
+// not be true indefinitely.)
+//
+// This convention ensures that the second-to-last decrement synchronizes with
+// (in the language of 1.10 in the C++ standard) the final decrement of a
+// reference count. Since reference counts are only updated using atomic
+// read-modify-write operations, this also extends to any earlier decrements.
+// (See "release sequence" in 1.10.)
+//
+// Since all operations on an object happen before the corresponding reference
+// count decrement, and all reference count decrements happen before the final
+// one, we are guaranteed that all other object accesses happen before the
+// object is destroyed.
+
+
+#define INITIAL_STRONG_VALUE (1<<28)
+
+#define MAX_COUNT 0xfffff
+
+// Test whether the argument is a clearly invalid strong reference count.
+// Used only for error checking on the value before an atomic decrement.
+// Intended to be very cheap.
+// Note that we cannot just check for excess decrements by comparing to zero
+// since the object would be deallocated before that.
+#define BAD_STRONG(c) \
+ ((c) == 0 || ((c) & (~(MAX_COUNT | INITIAL_STRONG_VALUE))) != 0)
+
+// Same for weak counts.
+#define BAD_WEAK(c) ((c) == 0 || ((c) & (~MAX_COUNT)) != 0)
+
+// name kept because prebuilts used to use it from inlining sp<> code
+void sp_report_stack_pointer() { LOG_ALWAYS_FATAL("RefBase used with stack pointer argument"); }
+
+// Check whether address is definitely on the calling stack. We actually check whether it is on
+// the same 4K page as the frame pointer.
+//
+// Assumptions:
+// - Pages are never smaller than 4K (MIN_PAGE_SIZE)
+// - Malloced memory never shares a page with a stack.
+//
+// It does not appear safe to broaden this check to include adjacent pages; apparently this code
+// is used in environments where there may not be a guard page below (at higher addresses than)
+// the bottom of the stack.
+static void check_not_on_stack(const void* ptr) {
+ static constexpr int MIN_PAGE_SIZE = 0x1000; // 4K. Safer than including sys/user.h.
+ static constexpr uintptr_t MIN_PAGE_MASK = ~static_cast<uintptr_t>(MIN_PAGE_SIZE - 1);
+ uintptr_t my_frame_address =
+ reinterpret_cast<uintptr_t>(__builtin_frame_address(0 /* this frame */));
+ if (((reinterpret_cast<uintptr_t>(ptr) ^ my_frame_address) & MIN_PAGE_MASK) == 0) {
+ sp_report_stack_pointer();
+ }
+}
+
+// ---------------------------------------------------------------------------
+
+class RefBase::weakref_impl : public RefBase::weakref_type
+{
+public:
+ std::atomic<int32_t> mStrong;
+ std::atomic<int32_t> mWeak;
+ RefBase* const mBase;
+ std::atomic<int32_t> mFlags;
+
+#if !DEBUG_REFS
+
+ explicit weakref_impl(RefBase* base)
+ : mStrong(INITIAL_STRONG_VALUE)
+ , mWeak(0)
+ , mBase(base)
+ , mFlags(OBJECT_LIFETIME_STRONG)
+ {
+ }
+
+ void addStrongRef(const void* /*id*/) { }
+ void removeStrongRef(const void* /*id*/) { }
+ void renameStrongRefId(const void* /*old_id*/, const void* /*new_id*/) { }
+ void addWeakRef(const void* /*id*/) { }
+ void removeWeakRef(const void* /*id*/) { }
+ void renameWeakRefId(const void* /*old_id*/, const void* /*new_id*/) { }
+ void printRefs() const { }
+ void trackMe(bool, bool) { }
+
+#else
+
+ weakref_impl(RefBase* base)
+ : mStrong(INITIAL_STRONG_VALUE)
+ , mWeak(0)
+ , mBase(base)
+ , mFlags(OBJECT_LIFETIME_STRONG)
+ , mStrongRefs(NULL)
+ , mWeakRefs(NULL)
+ , mTrackEnabled(!!DEBUG_REFS_ENABLED_BY_DEFAULT)
+ , mRetain(false)
+ {
+ }
+
+ ~weakref_impl()
+ {
+ bool dumpStack = false;
+ if (!mRetain && mStrongRefs != NULL) {
+ dumpStack = true;
+ ALOGE("Strong references remain:");
+ ref_entry* refs = mStrongRefs;
+ while (refs) {
+ char inc = refs->ref >= 0 ? '+' : '-';
+ ALOGD("\t%c ID %p (ref %d):", inc, refs->id, refs->ref);
+#if DEBUG_REFS_CALLSTACK_ENABLED && CALLSTACK_ENABLED
+ CallStack::logStack(LOG_TAG, refs->stack.get());
+#endif
+ refs = refs->next;
+ }
+ }
+
+ if (!mRetain && mWeakRefs != NULL) {
+ dumpStack = true;
+ ALOGE("Weak references remain!");
+ ref_entry* refs = mWeakRefs;
+ while (refs) {
+ char inc = refs->ref >= 0 ? '+' : '-';
+ ALOGD("\t%c ID %p (ref %d):", inc, refs->id, refs->ref);
+#if DEBUG_REFS_CALLSTACK_ENABLED && CALLSTACK_ENABLED
+ CallStack::logStack(LOG_TAG, refs->stack.get());
+#endif
+ refs = refs->next;
+ }
+ }
+ if (dumpStack) {
+ ALOGE("above errors at:");
+#if CALLSTACK_ENABLED
+ CallStack::logStack(LOG_TAG);
+#endif
+ }
+ }
+
+ void addStrongRef(const void* id) {
+ //ALOGD_IF(mTrackEnabled,
+ // "addStrongRef: RefBase=%p, id=%p", mBase, id);
+ addRef(&mStrongRefs, id, mStrong.load(std::memory_order_relaxed));
+ }
+
+ void removeStrongRef(const void* id) {
+ //ALOGD_IF(mTrackEnabled,
+ // "removeStrongRef: RefBase=%p, id=%p", mBase, id);
+ if (!mRetain) {
+ removeRef(&mStrongRefs, id);
+ } else {
+ addRef(&mStrongRefs, id, -mStrong.load(std::memory_order_relaxed));
+ }
+ }
+
+ void renameStrongRefId(const void* old_id, const void* new_id) {
+ //ALOGD_IF(mTrackEnabled,
+ // "renameStrongRefId: RefBase=%p, oid=%p, nid=%p",
+ // mBase, old_id, new_id);
+ renameRefsId(mStrongRefs, old_id, new_id);
+ }
+
+ void addWeakRef(const void* id) {
+ addRef(&mWeakRefs, id, mWeak.load(std::memory_order_relaxed));
+ }
+
+ void removeWeakRef(const void* id) {
+ if (!mRetain) {
+ removeRef(&mWeakRefs, id);
+ } else {
+ addRef(&mWeakRefs, id, -mWeak.load(std::memory_order_relaxed));
+ }
+ }
+
+ void renameWeakRefId(const void* old_id, const void* new_id) {
+ renameRefsId(mWeakRefs, old_id, new_id);
+ }
+
+ void trackMe(bool track, bool retain) {
+ mTrackEnabled = track;
+ mRetain = retain;
+ }
+
+ void printRefs() const
+ {
+ String8 text;
+
+ {
+ std::lock_guard<std::mutex> _l(mMutex);
+ char buf[128];
+ snprintf(buf, sizeof(buf),
+ "Strong references on RefBase %p (weakref_type %p):\n",
+ mBase, this);
+ text.append(buf);
+ printRefsLocked(&text, mStrongRefs);
+ snprintf(buf, sizeof(buf),
+ "Weak references on RefBase %p (weakref_type %p):\n",
+ mBase, this);
+ text.append(buf);
+ printRefsLocked(&text, mWeakRefs);
+ }
+
+ {
+ char name[100];
+ snprintf(name, sizeof(name), DEBUG_REFS_CALLSTACK_PATH "/%p.stack",
+ this);
+ int rc = open(name, O_RDWR | O_CREAT | O_APPEND, 0644);
+ if (rc >= 0) {
+ (void)write(rc, text.c_str(), text.length());
+ close(rc);
+ ALOGI("STACK TRACE for %p saved in %s", this, name);
+ }
+ else ALOGE("FAILED TO PRINT STACK TRACE for %p in %s: %s", this,
+ name, strerror(errno));
+ }
+ }
+
+private:
+ struct ref_entry
+ {
+ ref_entry* next;
+ const void* id;
+#if DEBUG_REFS_CALLSTACK_ENABLED && CALLSTACK_ENABLED
+ CallStack::CallStackUPtr stack;
+#endif
+ int32_t ref;
+ };
+
+ void addRef(ref_entry** refs, const void* id, int32_t mRef)
+ {
+ if (mTrackEnabled) {
+ std::lock_guard<std::mutex> _l(mMutex);
+
+ ref_entry* ref = new ref_entry;
+ // Reference count at the time of the snapshot, but before the
+ // update. Positive value means we increment, negative--we
+ // decrement the reference count.
+ ref->ref = mRef;
+ ref->id = id;
+#if DEBUG_REFS_CALLSTACK_ENABLED && CALLSTACK_ENABLED
+ ref->stack = CallStack::getCurrent(2);
+#endif
+ ref->next = *refs;
+ *refs = ref;
+ }
+ }
+
+ void removeRef(ref_entry** refs, const void* id)
+ {
+ if (mTrackEnabled) {
+ std::lock_guard<std::mutex> _l(mMutex);
+
+ ref_entry* const head = *refs;
+ ref_entry* ref = head;
+ while (ref != NULL) {
+ if (ref->id == id) {
+ *refs = ref->next;
+ delete ref;
+ return;
+ }
+ refs = &ref->next;
+ ref = *refs;
+ }
+
+ ALOGE("RefBase: removing id %p on RefBase %p"
+ "(weakref_type %p) that doesn't exist!",
+ id, mBase, this);
+
+ ref = head;
+ while (ref) {
+ char inc = ref->ref >= 0 ? '+' : '-';
+ ALOGD("\t%c ID %p (ref %d):", inc, ref->id, ref->ref);
+ ref = ref->next;
+ }
+
+#if CALLSTACK_ENABLED
+ CallStack::logStack(LOG_TAG);
+#endif
+ }
+ }
+
+ void renameRefsId(ref_entry* r, const void* old_id, const void* new_id)
+ {
+ if (mTrackEnabled) {
+ std::lock_guard<std::mutex> _l(mMutex);
+ ref_entry* ref = r;
+ while (ref != NULL) {
+ if (ref->id == old_id) {
+ ref->id = new_id;
+ }
+ ref = ref->next;
+ }
+ }
+ }
+
+ void printRefsLocked(String8* out, const ref_entry* refs) const
+ {
+ char buf[128];
+ while (refs) {
+ char inc = refs->ref >= 0 ? '+' : '-';
+ snprintf(buf, sizeof(buf), "\t%c ID %p (ref %d):\n",
+ inc, refs->id, refs->ref);
+ out->append(buf);
+#if DEBUG_REFS_CALLSTACK_ENABLED && CALLSTACK_ENABLED
+ out->append(CallStack::stackToString("\t\t", refs->stack.get()));
+#else
+ out->append("\t\t(call stacks disabled)");
+#endif
+ refs = refs->next;
+ }
+ }
+
+ mutable std::mutex mMutex;
+ ref_entry* mStrongRefs;
+ ref_entry* mWeakRefs;
+
+ bool mTrackEnabled;
+ // Collect stack traces on addref and removeref, instead of deleting the stack references
+ // on removeref that match the address ones.
+ bool mRetain;
+
+#endif
+};
+
+// ---------------------------------------------------------------------------
+
+void RefBase::incStrong(const void* id) const
+{
+ weakref_impl* const refs = mRefs;
+ refs->incWeak(id);
+
+ refs->addStrongRef(id);
+ const int32_t c = refs->mStrong.fetch_add(1, std::memory_order_relaxed);
+ ALOG_ASSERT(c > 0, "incStrong() called on %p after last strong ref", refs);
+#if PRINT_REFS
+ ALOGD("incStrong of %p from %p: cnt=%d\n", this, id, c);
+#endif
+ if (c != INITIAL_STRONG_VALUE) {
+ return;
+ }
+
+ check_not_on_stack(this);
+
+ int32_t old __unused = refs->mStrong.fetch_sub(INITIAL_STRONG_VALUE, std::memory_order_relaxed);
+ // A decStrong() must still happen after us.
+ ALOG_ASSERT(old > INITIAL_STRONG_VALUE, "0x%x too small", old);
+ refs->mBase->onFirstRef();
+}
+
+void RefBase::incStrongRequireStrong(const void* id) const {
+ weakref_impl* const refs = mRefs;
+ refs->incWeak(id);
+
+ refs->addStrongRef(id);
+ const int32_t c = refs->mStrong.fetch_add(1, std::memory_order_relaxed);
+
+ LOG_ALWAYS_FATAL_IF(c <= 0 || c == INITIAL_STRONG_VALUE,
+ "incStrongRequireStrong() called on %p which isn't already owned", refs);
+#if PRINT_REFS
+ ALOGD("incStrong (requiring strong) of %p from %p: cnt=%d\n", this, id, c);
+#endif
+}
+
+void RefBase::decStrong(const void* id) const
+{
+ weakref_impl* const refs = mRefs;
+ refs->removeStrongRef(id);
+ const int32_t c = refs->mStrong.fetch_sub(1, std::memory_order_release);
+#if PRINT_REFS
+ ALOGD("decStrong of %p from %p: cnt=%d\n", this, id, c);
+#endif
+ LOG_ALWAYS_FATAL_IF(BAD_STRONG(c), "decStrong() called on %p too many times",
+ refs);
+ if (c == 1) {
+ std::atomic_thread_fence(std::memory_order_acquire);
+ refs->mBase->onLastStrongRef(id);
+ int32_t flags = refs->mFlags.load(std::memory_order_relaxed);
+ if ((flags&OBJECT_LIFETIME_MASK) == OBJECT_LIFETIME_STRONG) {
+ delete this;
+ // The destructor does not delete refs in this case.
+ }
+ }
+ // Note that even with only strong reference operations, the thread
+ // deallocating this may not be the same as the thread deallocating refs.
+ // That's OK: all accesses to this happen before its deletion here,
+ // and all accesses to refs happen before its deletion in the final decWeak.
+ // The destructor can safely access mRefs because either it's deleting
+ // mRefs itself, or it's running entirely before the final mWeak decrement.
+ //
+ // Since we're doing atomic loads of `flags`, the static analyzer assumes
+ // they can change between `delete this;` and `refs->decWeak(id);`. This is
+ // not the case. The analyzer may become more okay with this patten when
+ // https://bugs.llvm.org/show_bug.cgi?id=34365 gets resolved. NOLINTNEXTLINE
+ refs->decWeak(id);
+}
+
+void RefBase::forceIncStrong(const void* id) const
+{
+ // Allows initial mStrong of 0 in addition to INITIAL_STRONG_VALUE.
+ // TODO: Better document assumptions.
+ weakref_impl* const refs = mRefs;
+ refs->incWeak(id);
+
+ refs->addStrongRef(id);
+ const int32_t c = refs->mStrong.fetch_add(1, std::memory_order_relaxed);
+ ALOG_ASSERT(c >= 0, "forceIncStrong called on %p after ref count underflow",
+ refs);
+#if PRINT_REFS
+ ALOGD("forceIncStrong of %p from %p: cnt=%d\n", this, id, c);
+#endif
+
+ switch (c) {
+ case INITIAL_STRONG_VALUE:
+ refs->mStrong.fetch_sub(INITIAL_STRONG_VALUE,
+ std::memory_order_relaxed);
+ FALLTHROUGH_INTENDED;
+ case 0:
+ refs->mBase->onFirstRef();
+ }
+}
+
+int32_t RefBase::getStrongCount() const
+{
+ // Debugging only; No memory ordering guarantees.
+ return mRefs->mStrong.load(std::memory_order_relaxed);
+}
+
+RefBase* RefBase::weakref_type::refBase() const
+{
+ return static_cast<const weakref_impl*>(this)->mBase;
+}
+
+void RefBase::weakref_type::incWeak(const void* id)
+{
+ weakref_impl* const impl = static_cast<weakref_impl*>(this);
+ impl->addWeakRef(id);
+ const int32_t c __unused = impl->mWeak.fetch_add(1,
+ std::memory_order_relaxed);
+ ALOG_ASSERT(c >= 0, "incWeak called on %p after last weak ref", this);
+}
+
+void RefBase::weakref_type::incWeakRequireWeak(const void* id)
+{
+ weakref_impl* const impl = static_cast<weakref_impl*>(this);
+ impl->addWeakRef(id);
+ const int32_t c __unused = impl->mWeak.fetch_add(1,
+ std::memory_order_relaxed);
+ LOG_ALWAYS_FATAL_IF(c <= 0, "incWeakRequireWeak called on %p which has no weak refs", this);
+}
+
+void RefBase::weakref_type::decWeak(const void* id)
+{
+ weakref_impl* const impl = static_cast<weakref_impl*>(this);
+ impl->removeWeakRef(id);
+ const int32_t c = impl->mWeak.fetch_sub(1, std::memory_order_release);
+ LOG_ALWAYS_FATAL_IF(BAD_WEAK(c), "decWeak called on %p too many times",
+ this);
+ if (c != 1) return;
+ atomic_thread_fence(std::memory_order_acquire);
+
+ int32_t flags = impl->mFlags.load(std::memory_order_relaxed);
+ if ((flags&OBJECT_LIFETIME_MASK) == OBJECT_LIFETIME_STRONG) {
+ // This is the regular lifetime case. The object is destroyed
+ // when the last strong reference goes away. Since weakref_impl
+ // outlives the object, it is not destroyed in the dtor, and
+ // we'll have to do it here.
+ if (impl->mStrong.load(std::memory_order_relaxed)
+ == INITIAL_STRONG_VALUE) {
+ // Decrementing a weak count to zero when object never had a strong
+ // reference. We assume it acquired a weak reference early, e.g.
+ // in the constructor, and will eventually be properly destroyed,
+ // usually via incrementing and decrementing the strong count.
+ // Thus we no longer do anything here. We log this case, since it
+ // seems to be extremely rare, and should not normally occur. We
+ // used to deallocate mBase here, so this may now indicate a leak.
+ ALOGW("RefBase: Object at %p lost last weak reference "
+ "before it had a strong reference", impl->mBase);
+ } else {
+ // ALOGV("Freeing refs %p of old RefBase %p\n", this, impl->mBase);
+ delete impl;
+ }
+ } else {
+ // This is the OBJECT_LIFETIME_WEAK case. The last weak-reference
+ // is gone, we can destroy the object.
+ impl->mBase->onLastWeakRef(id);
+ delete impl->mBase;
+ }
+}
+
+bool RefBase::weakref_type::attemptIncStrong(const void* id)
+{
+ incWeak(id);
+
+ weakref_impl* const impl = static_cast<weakref_impl*>(this);
+ int32_t curCount = impl->mStrong.load(std::memory_order_relaxed);
+
+ ALOG_ASSERT(curCount >= 0,
+ "attemptIncStrong called on %p after underflow", this);
+
+ while (curCount > 0 && curCount != INITIAL_STRONG_VALUE) {
+ // we're in the easy/common case of promoting a weak-reference
+ // from an existing strong reference.
+ if (impl->mStrong.compare_exchange_weak(curCount, curCount+1,
+ std::memory_order_relaxed)) {
+ break;
+ }
+ // the strong count has changed on us, we need to re-assert our
+ // situation. curCount was updated by compare_exchange_weak.
+ }
+
+ if (curCount <= 0 || curCount == INITIAL_STRONG_VALUE) {
+ // we're now in the harder case of either:
+ // - there never was a strong reference on us
+ // - or, all strong references have been released
+ int32_t flags = impl->mFlags.load(std::memory_order_relaxed);
+ if ((flags&OBJECT_LIFETIME_MASK) == OBJECT_LIFETIME_STRONG) {
+ // this object has a "normal" life-time, i.e.: it gets destroyed
+ // when the last strong reference goes away
+ if (curCount <= 0) {
+ // the last strong-reference got released, the object cannot
+ // be revived.
+ decWeak(id);
+ return false;
+ }
+
+ // here, curCount == INITIAL_STRONG_VALUE, which means
+ // there never was a strong-reference, so we can try to
+ // promote this object; we need to do that atomically.
+ while (curCount > 0) {
+ if (impl->mStrong.compare_exchange_weak(curCount, curCount+1,
+ std::memory_order_relaxed)) {
+ break;
+ }
+ // the strong count has changed on us, we need to re-assert our
+ // situation (e.g.: another thread has inc/decStrong'ed us)
+ // curCount has been updated.
+ }
+
+ if (curCount <= 0) {
+ // promote() failed, some other thread destroyed us in the
+ // meantime (i.e.: strong count reached zero).
+ decWeak(id);
+ return false;
+ }
+ } else {
+ // this object has an "extended" life-time, i.e.: it can be
+ // revived from a weak-reference only.
+ // Ask the object's implementation if it agrees to be revived
+ if (!impl->mBase->onIncStrongAttempted(FIRST_INC_STRONG, id)) {
+ // it didn't so give-up.
+ decWeak(id);
+ return false;
+ }
+ // grab a strong-reference, which is always safe due to the
+ // extended life-time.
+ curCount = impl->mStrong.fetch_add(1, std::memory_order_relaxed);
+ // If the strong reference count has already been incremented by
+ // someone else, the implementor of onIncStrongAttempted() is holding
+ // an unneeded reference. So call onLastStrongRef() here to remove it.
+ // (No, this is not pretty.) Note that we MUST NOT do this if we
+ // are in fact acquiring the first reference.
+ if (curCount != 0 && curCount != INITIAL_STRONG_VALUE) {
+ impl->mBase->onLastStrongRef(id);
+ }
+ }
+ }
+
+ impl->addStrongRef(id);
+
+#if PRINT_REFS
+ ALOGD("attemptIncStrong of %p from %p: cnt=%d\n", this, id, curCount);
+#endif
+
+ // curCount is the value of mStrong before we incremented it.
+ // Now we need to fix-up the count if it was INITIAL_STRONG_VALUE.
+ // This must be done safely, i.e.: handle the case where several threads
+ // were here in attemptIncStrong().
+ // curCount > INITIAL_STRONG_VALUE is OK, and can happen if we're doing
+ // this in the middle of another incStrong. The subtraction is handled
+ // by the thread that started with INITIAL_STRONG_VALUE.
+ if (curCount == INITIAL_STRONG_VALUE) {
+ impl->mStrong.fetch_sub(INITIAL_STRONG_VALUE,
+ std::memory_order_relaxed);
+ }
+
+ return true;
+}
+
+bool RefBase::weakref_type::attemptIncWeak(const void* id)
+{
+ weakref_impl* const impl = static_cast<weakref_impl*>(this);
+
+ int32_t curCount = impl->mWeak.load(std::memory_order_relaxed);
+ ALOG_ASSERT(curCount >= 0, "attemptIncWeak called on %p after underflow",
+ this);
+ while (curCount > 0) {
+ if (impl->mWeak.compare_exchange_weak(curCount, curCount+1,
+ std::memory_order_relaxed)) {
+ break;
+ }
+ // curCount has been updated.
+ }
+
+ if (curCount > 0) {
+ impl->addWeakRef(id);
+ }
+
+ return curCount > 0;
+}
+
+int32_t RefBase::weakref_type::getWeakCount() const
+{
+ // Debug only!
+ return static_cast<const weakref_impl*>(this)->mWeak
+ .load(std::memory_order_relaxed);
+}
+
+void RefBase::weakref_type::printRefs() const
+{
+ static_cast<const weakref_impl*>(this)->printRefs();
+}
+
+void RefBase::weakref_type::trackMe(bool enable, bool retain)
+{
+ static_cast<weakref_impl*>(this)->trackMe(enable, retain);
+}
+
+RefBase::weakref_type* RefBase::createWeak(const void* id) const
+{
+ mRefs->incWeak(id);
+ return mRefs;
+}
+
+RefBase::weakref_type* RefBase::getWeakRefs() const
+{
+ return mRefs;
+}
+
+RefBase::RefBase()
+ : mRefs(new weakref_impl(this))
+{
+}
+
+RefBase::~RefBase()
+{
+ int32_t flags = mRefs->mFlags.load(std::memory_order_relaxed);
+ // Life-time of this object is extended to WEAK, in
+ // which case weakref_impl doesn't out-live the object and we
+ // can free it now.
+ if ((flags & OBJECT_LIFETIME_MASK) == OBJECT_LIFETIME_WEAK) {
+ // It's possible that the weak count is not 0 if the object
+ // re-acquired a weak reference in its destructor
+ if (mRefs->mWeak.load(std::memory_order_relaxed) == 0) {
+ delete mRefs;
+ }
+ } else {
+ int32_t strongs = mRefs->mStrong.load(std::memory_order_relaxed);
+
+ if (strongs == INITIAL_STRONG_VALUE) {
+ // We never acquired a strong reference on this object.
+
+ // It would be nice to make this fatal, but many places use RefBase on the stack.
+ // However, this is dangerous because it's also common for code to use the
+ // sp<T>(T*) constructor, assuming that if the object is around, it is already
+ // owned by an sp<>.
+ ALOGW("RefBase: Explicit destruction, weak count = %d (in %p). Use sp<> to manage this "
+ "object.",
+ mRefs->mWeak.load(), this);
+
+#if CALLSTACK_ENABLED
+ CallStack::logStack(LOG_TAG);
+#endif
+ } else if (strongs != 0) {
+ LOG_ALWAYS_FATAL("RefBase: object %p with strong count %d deleted. Double owned?", this,
+ strongs);
+ }
+ }
+ // For debugging purposes, clear mRefs. Ineffective against outstanding wp's.
+ const_cast<weakref_impl*&>(mRefs) = nullptr;
+}
+
+void RefBase::extendObjectLifetime(int32_t mode)
+{
+ check_not_on_stack(this);
+
+ // Must be happens-before ordered with respect to construction or any
+ // operation that could destroy the object.
+ mRefs->mFlags.fetch_or(mode, std::memory_order_relaxed);
+}
+
+void RefBase::onFirstRef()
+{
+}
+
+void RefBase::onLastStrongRef(const void* /*id*/)
+{
+}
+
+bool RefBase::onIncStrongAttempted(uint32_t flags, const void* /*id*/)
+{
+ return (flags&FIRST_INC_STRONG) ? true : false;
+}
+
+void RefBase::onLastWeakRef(const void* /*id*/)
+{
+}
+
+// ---------------------------------------------------------------------------
+
+#if DEBUG_REFS
+void RefBase::renameRefs(size_t n, const ReferenceRenamer& renamer) {
+ for (size_t i=0 ; i<n ; i++) {
+ renamer(i);
+ }
+}
+#else
+void RefBase::renameRefs(size_t /*n*/, const ReferenceRenamer& /*renamer*/) { }
+#endif
+
+void RefBase::renameRefId(weakref_type* ref,
+ const void* old_id, const void* new_id) {
+ weakref_impl* const impl = static_cast<weakref_impl*>(ref);
+ impl->renameStrongRefId(old_id, new_id);
+ impl->renameWeakRefId(old_id, new_id);
+}
+
+void RefBase::renameRefId(RefBase* ref,
+ const void* old_id, const void* new_id) {
+ ref->mRefs->renameStrongRefId(old_id, new_id);
+ ref->mRefs->renameWeakRefId(old_id, new_id);
+}
+
+}; // namespace android
diff --git a/libutils/binder/RefBase_fuzz.cpp b/libutils/binder/RefBase_fuzz.cpp
new file mode 100644
index 0000000..05f47a0
--- /dev/null
+++ b/libutils/binder/RefBase_fuzz.cpp
@@ -0,0 +1,205 @@
+/*
+ * Copyright 2020 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.
+ */
+
+#define LOG_TAG "RefBaseFuzz"
+
+#include <thread>
+
+#include "fuzzer/FuzzedDataProvider.h"
+#include "log/log.h"
+#include "utils/RWLock.h"
+#include "utils/RefBase.h"
+#include "utils/StrongPointer.h"
+
+using android::RefBase;
+using android::RWLock;
+using android::sp;
+using android::wp;
+
+static constexpr int kMaxOperations = 100;
+static constexpr int kMaxThreads = 10;
+struct RefBaseSubclass : public RefBase {
+ public:
+ RefBaseSubclass(bool* deletedCheck, RWLock& deletedMtx)
+ : mDeleted(deletedCheck), mRwLock(deletedMtx) {
+ RWLock::AutoWLock lock(mRwLock);
+ *mDeleted = false;
+ extendObjectLifetime(OBJECT_LIFETIME_WEAK);
+ }
+
+ virtual ~RefBaseSubclass() {
+ RWLock::AutoWLock lock(mRwLock);
+ *mDeleted = true;
+ }
+
+ private:
+ bool* mDeleted;
+ android::RWLock& mRwLock;
+};
+
+// A thread-specific state object for ref
+struct RefThreadState {
+ size_t strongCount = 0;
+ size_t weakCount = 0;
+};
+
+RWLock gRefDeletedLock;
+bool gRefDeleted = false;
+bool gHasModifiedRefs = false;
+RefBaseSubclass* ref;
+RefBase::weakref_type* weakRefs;
+
+// These operations don't need locks as they explicitly check per-thread counts before running
+// they also have the potential to write to gRefDeleted, so must not be locked.
+const std::vector<std::function<void(RefThreadState*)>> kUnlockedOperations = {
+ [](RefThreadState* refState) -> void {
+ if (refState->strongCount > 0) {
+ ref->decStrong(nullptr);
+ gHasModifiedRefs = true;
+ refState->strongCount--;
+ }
+ },
+ [](RefThreadState* refState) -> void {
+ if (refState->weakCount > 0) {
+ weakRefs->decWeak(nullptr);
+ gHasModifiedRefs = true;
+ refState->weakCount--;
+ }
+ },
+};
+
+const std::vector<std::function<void(RefThreadState*)>> kMaybeLockedOperations = {
+ // Read-only operations
+ [](RefThreadState*) -> void { ref->getStrongCount(); },
+ [](RefThreadState*) -> void { weakRefs->getWeakCount(); },
+ [](RefThreadState*) -> void { ref->printRefs(); },
+
+ // Read/write operations
+ [](RefThreadState* refState) -> void {
+ ref->incStrong(nullptr);
+ gHasModifiedRefs = true;
+ refState->strongCount++;
+ },
+ [](RefThreadState* refState) -> void {
+ ref->forceIncStrong(nullptr);
+ gHasModifiedRefs = true;
+ refState->strongCount++;
+ },
+ [](RefThreadState* refState) -> void {
+ ref->createWeak(nullptr);
+ gHasModifiedRefs = true;
+ refState->weakCount++;
+ },
+ [](RefThreadState* refState) -> void {
+ // This will increment weak internally, then attempt to
+ // promote it to strong. If it fails, it decrements weak.
+ // If it succeeds, the weak is converted to strong.
+ // Both cases net no weak reference change.
+ if (weakRefs->attemptIncStrong(nullptr)) {
+ refState->strongCount++;
+ gHasModifiedRefs = true;
+ }
+ },
+ [](RefThreadState* refState) -> void {
+ if (weakRefs->attemptIncWeak(nullptr)) {
+ refState->weakCount++;
+ gHasModifiedRefs = true;
+ }
+ },
+ [](RefThreadState* refState) -> void {
+ weakRefs->incWeak(nullptr);
+ gHasModifiedRefs = true;
+ refState->weakCount++;
+ },
+};
+
+void loop(const std::vector<uint8_t>& fuzzOps) {
+ RefThreadState state;
+ uint8_t lockedOpSize = kMaybeLockedOperations.size();
+ uint8_t totalOperationTypes = lockedOpSize + kUnlockedOperations.size();
+ for (auto op : fuzzOps) {
+ auto opVal = op % totalOperationTypes;
+ if (opVal >= lockedOpSize) {
+ kUnlockedOperations[opVal % lockedOpSize](&state);
+ } else {
+ // We only need to lock if we have no strong or weak count
+ bool shouldLock = state.strongCount == 0 && state.weakCount == 0;
+ if (shouldLock) {
+ gRefDeletedLock.readLock();
+ // If ref has deleted itself, we can no longer fuzz on this thread.
+ if (gRefDeleted) {
+ // Unlock since we're exiting the loop here.
+ gRefDeletedLock.unlock();
+ return;
+ }
+ }
+ // Execute the locked operation
+ kMaybeLockedOperations[opVal](&state);
+ // Unlock if we locked.
+ if (shouldLock) {
+ gRefDeletedLock.unlock();
+ }
+ }
+ }
+
+ // Instead of explicitly freeing this, we're going to remove our weak and
+ // strong references.
+ for (; state.weakCount > 0; state.weakCount--) {
+ weakRefs->decWeak(nullptr);
+ }
+
+ // Clean up any strong references
+ for (; state.strongCount > 0; state.strongCount--) {
+ ref->decStrong(nullptr);
+ }
+}
+
+void spawnThreads(FuzzedDataProvider* dataProvider) {
+ std::vector<std::thread> threads = std::vector<std::thread>();
+
+ // Get the number of threads to generate
+ uint8_t count = dataProvider->ConsumeIntegralInRange<uint8_t>(1, kMaxThreads);
+ // Generate threads
+ for (uint8_t i = 0; i < count; i++) {
+ uint8_t opCount = dataProvider->ConsumeIntegralInRange<uint8_t>(1, kMaxOperations);
+ std::vector<uint8_t> threadOperations = dataProvider->ConsumeBytes<uint8_t>(opCount);
+ std::thread tmpThread = std::thread(loop, threadOperations);
+ threads.push_back(std::move(tmpThread));
+ }
+
+ for (auto& th : threads) {
+ th.join();
+ }
+}
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+ gHasModifiedRefs = false;
+ ref = new RefBaseSubclass(&gRefDeleted, gRefDeletedLock);
+ weakRefs = ref->getWeakRefs();
+ // Since we are modifying flags, (flags & OBJECT_LIFETIME_MASK) == OBJECT_LIFETIME_WEAK
+ // is true. The destructor for RefBase should clean up weakrefs because of this.
+ FuzzedDataProvider dataProvider(data, size);
+ spawnThreads(&dataProvider);
+ LOG_ALWAYS_FATAL_IF(!gHasModifiedRefs && gRefDeleted, "ref(%p) was prematurely deleted!", ref);
+ // We need to explicitly delete this object
+ // if no refs have been added or deleted.
+ if (!gHasModifiedRefs && !gRefDeleted) {
+ delete ref;
+ }
+ LOG_ALWAYS_FATAL_IF(gHasModifiedRefs && !gRefDeleted,
+ "ref(%p) should be deleted, is it leaking?", ref);
+ return 0;
+}
diff --git a/libutils/binder/RefBase_test.cpp b/libutils/binder/RefBase_test.cpp
new file mode 100644
index 0000000..d675598
--- /dev/null
+++ b/libutils/binder/RefBase_test.cpp
@@ -0,0 +1,447 @@
+/*
+ * Copyright (C) 2016 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 <gtest/gtest.h>
+
+#include <utils/StrongPointer.h>
+#include <utils/RefBase.h>
+
+#include <thread>
+#include <atomic>
+#include <sched.h>
+#include <errno.h>
+
+// Enhanced version of StrongPointer_test, but using RefBase underneath.
+
+using namespace android;
+
+static constexpr int NITERS = 500000;
+
+static constexpr int INITIAL_STRONG_VALUE = 1 << 28; // Mirroring RefBase definition.
+
+class Foo : public RefBase {
+public:
+ Foo(bool* deleted_check) : mDeleted(deleted_check) {
+ *mDeleted = false;
+ }
+
+ ~Foo() {
+ *mDeleted = true;
+ }
+private:
+ bool* mDeleted;
+};
+
+// A version of Foo that ensures that all objects are allocated at the same
+// address. No more than one can be allocated at a time. Thread-hostile.
+class FooFixedAlloc : public RefBase {
+public:
+ static void* operator new(size_t size) {
+ if (mAllocCount != 0) {
+ abort();
+ }
+ mAllocCount = 1;
+ if (theMemory == nullptr) {
+ theMemory = malloc(size);
+ }
+ return theMemory;
+ }
+
+ static void operator delete(void *p) {
+ if (mAllocCount != 1 || p != theMemory) {
+ abort();
+ }
+ mAllocCount = 0;
+ }
+
+ FooFixedAlloc(bool* deleted_check) : mDeleted(deleted_check) {
+ *mDeleted = false;
+ }
+
+ ~FooFixedAlloc() {
+ *mDeleted = true;
+ }
+private:
+ bool* mDeleted;
+ static int mAllocCount;
+ static void* theMemory;
+};
+
+int FooFixedAlloc::mAllocCount(0);
+void* FooFixedAlloc::theMemory(nullptr);
+
+TEST(RefBase, StrongMoves) {
+ bool isDeleted;
+ Foo* foo = new Foo(&isDeleted);
+ ASSERT_EQ(INITIAL_STRONG_VALUE, foo->getStrongCount());
+ ASSERT_FALSE(isDeleted) << "Already deleted...?";
+ sp<Foo> sp1(foo);
+ wp<Foo> wp1(sp1);
+ ASSERT_EQ(1, foo->getStrongCount());
+ // Weak count includes both strong and weak references.
+ ASSERT_EQ(2, foo->getWeakRefs()->getWeakCount());
+ {
+ sp<Foo> sp2 = std::move(sp1);
+ ASSERT_EQ(1, foo->getStrongCount())
+ << "std::move failed, incremented refcnt";
+ ASSERT_EQ(nullptr, sp1.get()) << "std::move failed, sp1 is still valid";
+ // The strong count isn't increasing, let's double check the old object
+ // is properly reset and doesn't early delete
+ sp1 = std::move(sp2);
+ }
+ ASSERT_FALSE(isDeleted) << "deleted too early! still has a reference!";
+ {
+ // Now let's double check it deletes on time
+ sp<Foo> sp2 = std::move(sp1);
+ }
+ ASSERT_TRUE(isDeleted) << "foo was leaked!";
+ ASSERT_TRUE(wp1.promote().get() == nullptr);
+}
+
+TEST(RefBase, WeakCopies) {
+ bool isDeleted;
+ Foo* foo = new Foo(&isDeleted);
+ EXPECT_EQ(0, foo->getWeakRefs()->getWeakCount());
+ ASSERT_FALSE(isDeleted) << "Foo (weak) already deleted...?";
+ wp<Foo> wp1(foo);
+ EXPECT_EQ(1, foo->getWeakRefs()->getWeakCount());
+ {
+ wp<Foo> wp2 = wp1;
+ ASSERT_EQ(2, foo->getWeakRefs()->getWeakCount());
+ }
+ EXPECT_EQ(1, foo->getWeakRefs()->getWeakCount());
+ ASSERT_FALSE(isDeleted) << "deleted too early! still has a reference!";
+ wp1 = nullptr;
+ ASSERT_FALSE(isDeleted) << "Deletion on wp destruction should no longer occur";
+}
+
+TEST(RefBase, Comparisons) {
+ bool isDeleted, isDeleted2, isDeleted3;
+ Foo* foo = new Foo(&isDeleted);
+ Foo* foo2 = new Foo(&isDeleted2);
+ sp<Foo> sp1(foo);
+ sp<Foo> sp2(foo2);
+ wp<Foo> wp1(sp1);
+ wp<Foo> wp2(sp1);
+ wp<Foo> wp3(sp2);
+ ASSERT_TRUE(wp1 == wp2);
+ ASSERT_TRUE(wp1 == sp1);
+ ASSERT_TRUE(wp3 == sp2);
+ ASSERT_TRUE(wp1 != sp2);
+ ASSERT_TRUE(wp1 <= wp2);
+ ASSERT_TRUE(wp1 >= wp2);
+ ASSERT_FALSE(wp1 != wp2);
+ ASSERT_FALSE(wp1 > wp2);
+ ASSERT_FALSE(wp1 < wp2);
+ ASSERT_FALSE(sp1 == sp2);
+ ASSERT_TRUE(sp1 != sp2);
+ bool sp1_smaller = sp1 < sp2;
+ wp<Foo>wp_smaller = sp1_smaller ? wp1 : wp3;
+ wp<Foo>wp_larger = sp1_smaller ? wp3 : wp1;
+ ASSERT_TRUE(wp_smaller < wp_larger);
+ ASSERT_TRUE(wp_smaller != wp_larger);
+ ASSERT_TRUE(wp_smaller <= wp_larger);
+ ASSERT_FALSE(wp_smaller == wp_larger);
+ ASSERT_FALSE(wp_smaller > wp_larger);
+ ASSERT_FALSE(wp_smaller >= wp_larger);
+ sp2 = nullptr;
+ ASSERT_TRUE(isDeleted2);
+ ASSERT_FALSE(isDeleted);
+ ASSERT_FALSE(wp3 == sp2);
+ // Comparison results on weak pointers should not be affected.
+ ASSERT_TRUE(wp_smaller < wp_larger);
+ ASSERT_TRUE(wp_smaller != wp_larger);
+ ASSERT_TRUE(wp_smaller <= wp_larger);
+ ASSERT_FALSE(wp_smaller == wp_larger);
+ ASSERT_FALSE(wp_smaller > wp_larger);
+ ASSERT_FALSE(wp_smaller >= wp_larger);
+ wp2 = nullptr;
+ ASSERT_FALSE(wp1 == wp2);
+ ASSERT_TRUE(wp1 != wp2);
+ wp1.clear();
+ ASSERT_TRUE(wp1 == wp2);
+ ASSERT_FALSE(wp1 != wp2);
+ wp3.clear();
+ ASSERT_TRUE(wp1 == wp3);
+ ASSERT_FALSE(wp1 != wp3);
+ ASSERT_FALSE(isDeleted);
+ sp1.clear();
+ ASSERT_TRUE(isDeleted);
+ ASSERT_TRUE(sp1 == sp2);
+ // Try to check that null pointers are properly initialized.
+ {
+ // Try once with non-null, to maximize chances of getting junk on the
+ // stack.
+ sp<Foo> sp3(new Foo(&isDeleted3));
+ wp<Foo> wp4(sp3);
+ wp<Foo> wp5;
+ ASSERT_FALSE(wp4 == wp5);
+ ASSERT_TRUE(wp4 != wp5);
+ ASSERT_FALSE(sp3 == wp5);
+ ASSERT_FALSE(wp5 == sp3);
+ ASSERT_TRUE(sp3 != wp5);
+ ASSERT_TRUE(wp5 != sp3);
+ ASSERT_TRUE(sp3 == wp4);
+ }
+ {
+ sp<Foo> sp3;
+ wp<Foo> wp4(sp3);
+ wp<Foo> wp5;
+ ASSERT_TRUE(wp4 == wp5);
+ ASSERT_FALSE(wp4 != wp5);
+ ASSERT_TRUE(sp3 == wp5);
+ ASSERT_TRUE(wp5 == sp3);
+ ASSERT_FALSE(sp3 != wp5);
+ ASSERT_FALSE(wp5 != sp3);
+ ASSERT_TRUE(sp3 == wp4);
+ }
+}
+
+// Check whether comparison against dead wp works, even if the object referenced
+// by the new wp happens to be at the same address.
+TEST(RefBase, ReplacedComparison) {
+ bool isDeleted, isDeleted2;
+ FooFixedAlloc* foo = new FooFixedAlloc(&isDeleted);
+ sp<FooFixedAlloc> sp1(foo);
+ wp<FooFixedAlloc> wp1(sp1);
+ ASSERT_TRUE(wp1 == sp1);
+ sp1.clear(); // Deallocates the object.
+ ASSERT_TRUE(isDeleted);
+ FooFixedAlloc* foo2 = new FooFixedAlloc(&isDeleted2);
+ ASSERT_FALSE(isDeleted2);
+ ASSERT_EQ(foo, foo2); // Not technically a legal comparison, but ...
+ sp<FooFixedAlloc> sp2(foo2);
+ wp<FooFixedAlloc> wp2(sp2);
+ ASSERT_TRUE(sp2 == wp2);
+ ASSERT_FALSE(sp2 != wp2);
+ ASSERT_TRUE(sp2 != wp1);
+ ASSERT_FALSE(sp2 == wp1);
+ ASSERT_FALSE(sp2 == sp1); // sp1 is null.
+ ASSERT_FALSE(wp1 == wp2); // wp1 refers to old object.
+ ASSERT_TRUE(wp1 != wp2);
+ ASSERT_TRUE(wp1 > wp2 || wp1 < wp2);
+ ASSERT_TRUE(wp1 >= wp2 || wp1 <= wp2);
+ ASSERT_FALSE(wp1 >= wp2 && wp1 <= wp2);
+ ASSERT_FALSE(wp1 == nullptr);
+ wp1 = sp2;
+ ASSERT_TRUE(wp1 == wp2);
+ ASSERT_FALSE(wp1 != wp2);
+}
+
+TEST(RefBase, AssertWeakRefExistsSuccess) {
+ bool isDeleted;
+ sp<Foo> foo = sp<Foo>::make(&isDeleted);
+ wp<Foo> weakFoo = foo;
+
+ EXPECT_EQ(weakFoo, wp<Foo>::fromExisting(foo.get()));
+ EXPECT_EQ(weakFoo.unsafe_get(), wp<Foo>::fromExisting(foo.get()).unsafe_get());
+
+ EXPECT_FALSE(isDeleted);
+ foo = nullptr;
+ EXPECT_TRUE(isDeleted);
+}
+
+TEST(RefBase, AssertWeakRefExistsDeath) {
+ // uses some other refcounting method, or none at all
+ bool isDeleted;
+ Foo* foo = new Foo(&isDeleted);
+
+ // can only get a valid wp<> object when you construct it from an sp<>
+ EXPECT_DEATH(wp<Foo>::fromExisting(foo), "");
+
+ delete foo;
+}
+
+TEST(RefBase, DoubleOwnershipDeath) {
+ bool isDeleted;
+ auto foo = sp<Foo>::make(&isDeleted);
+
+ // if something else thinks it owns foo, should die
+ EXPECT_DEATH(delete foo.get(), "");
+
+ EXPECT_FALSE(isDeleted);
+}
+
+TEST(RefBase, StackOwnershipDeath) {
+ bool isDeleted;
+ EXPECT_DEATH({ Foo foo(&isDeleted); foo.incStrong(nullptr); }, "");
+}
+
+// Set up a situation in which we race with visit2AndRremove() to delete
+// 2 strong references. Bar destructor checks that there are no early
+// deletions and prior updates are visible to destructor.
+class Bar : public RefBase {
+public:
+ Bar(std::atomic<int>* delete_count) : mVisited1(false), mVisited2(false),
+ mDeleteCount(delete_count) {
+ }
+
+ ~Bar() {
+ EXPECT_TRUE(mVisited1);
+ EXPECT_TRUE(mVisited2);
+ (*mDeleteCount)++;
+ }
+ bool mVisited1;
+ bool mVisited2;
+private:
+ std::atomic<int>* mDeleteCount;
+};
+
+static sp<Bar> buffer;
+static std::atomic<bool> bufferFull(false);
+
+// Wait until bufferFull has value val.
+static inline void waitFor(bool val) {
+ while (bufferFull != val) {}
+}
+
+cpu_set_t otherCpus;
+
+// Divide the cpus we're allowed to run on into myCpus and otherCpus.
+// Set origCpus to the processors we were originally allowed to run on.
+// Return false if origCpus doesn't include at least processors 0 and 1.
+static bool setExclusiveCpus(cpu_set_t* origCpus /* out */,
+ cpu_set_t* myCpus /* out */, cpu_set_t* otherCpus) {
+ if (sched_getaffinity(0, sizeof(cpu_set_t), origCpus) != 0) {
+ return false;
+ }
+ if (!CPU_ISSET(0, origCpus) || !CPU_ISSET(1, origCpus)) {
+ return false;
+ }
+ CPU_ZERO(myCpus);
+ CPU_ZERO(otherCpus);
+ CPU_OR(myCpus, myCpus, origCpus);
+ CPU_OR(otherCpus, otherCpus, origCpus);
+ for (unsigned i = 0; i < CPU_SETSIZE; ++i) {
+ // I get the even cores, the other thread gets the odd ones.
+ if (i & 1) {
+ CPU_CLR(i, myCpus);
+ } else {
+ CPU_CLR(i, otherCpus);
+ }
+ }
+ return true;
+}
+
+static void visit2AndRemove() {
+ if (sched_setaffinity(0, sizeof(cpu_set_t), &otherCpus) != 0) {
+ FAIL() << "setaffinity returned:" << errno;
+ }
+ for (int i = 0; i < NITERS; ++i) {
+ waitFor(true);
+ buffer->mVisited2 = true;
+ buffer = nullptr;
+ bufferFull = false;
+ }
+}
+
+TEST(RefBase, RacingDestructors) {
+ cpu_set_t origCpus;
+ cpu_set_t myCpus;
+ // Restrict us and the helper thread to disjoint cpu sets.
+ // This prevents us from getting scheduled against each other,
+ // which would be atrociously slow.
+ if (setExclusiveCpus(&origCpus, &myCpus, &otherCpus)) {
+ std::thread t(visit2AndRemove);
+ std::atomic<int> deleteCount(0);
+ if (sched_setaffinity(0, sizeof(cpu_set_t), &myCpus) != 0) {
+ FAIL() << "setaffinity returned:" << errno;
+ }
+ for (int i = 0; i < NITERS; ++i) {
+ waitFor(false);
+ Bar* bar = new Bar(&deleteCount);
+ sp<Bar> sp3(bar);
+ buffer = sp3;
+ bufferFull = true;
+ ASSERT_TRUE(bar->getStrongCount() >= 1);
+ // Weak count includes strong count.
+ ASSERT_TRUE(bar->getWeakRefs()->getWeakCount() >= 1);
+ sp3->mVisited1 = true;
+ sp3 = nullptr;
+ }
+ t.join();
+ if (sched_setaffinity(0, sizeof(cpu_set_t), &origCpus) != 0) {
+ FAIL();
+ }
+ ASSERT_EQ(NITERS, deleteCount) << "Deletions missed!";
+ } // Otherwise this is slow and probably pointless on a uniprocessor.
+}
+
+static wp<Bar> wpBuffer;
+static std::atomic<bool> wpBufferFull(false);
+
+// Wait until wpBufferFull has value val.
+static inline void wpWaitFor(bool val) {
+ while (wpBufferFull != val) {}
+}
+
+static void visit3AndRemove() {
+ if (sched_setaffinity(0, sizeof(cpu_set_t), &otherCpus) != 0) {
+ FAIL() << "setaffinity returned:" << errno;
+ }
+ for (int i = 0; i < NITERS; ++i) {
+ wpWaitFor(true);
+ {
+ sp<Bar> sp1 = wpBuffer.promote();
+ // We implicitly check that sp1 != NULL
+ sp1->mVisited2 = true;
+ }
+ wpBuffer = nullptr;
+ wpBufferFull = false;
+ }
+}
+
+TEST(RefBase, RacingPromotions) {
+ cpu_set_t origCpus;
+ cpu_set_t myCpus;
+ // Restrict us and the helper thread to disjoint cpu sets.
+ // This prevents us from getting scheduled against each other,
+ // which would be atrociously slow.
+ if (setExclusiveCpus(&origCpus, &myCpus, &otherCpus)) {
+ std::thread t(visit3AndRemove);
+ std::atomic<int> deleteCount(0);
+ if (sched_setaffinity(0, sizeof(cpu_set_t), &myCpus) != 0) {
+ FAIL() << "setaffinity returned:" << errno;
+ }
+ for (int i = 0; i < NITERS; ++i) {
+ Bar* bar = new Bar(&deleteCount);
+ wp<Bar> wp1(bar);
+ bar->mVisited1 = true;
+ if (i % (NITERS / 10) == 0) {
+ // Do this rarely, since it generates a log message.
+ wp1 = nullptr; // No longer destroys the object.
+ wp1 = bar;
+ }
+ wpBuffer = wp1;
+ ASSERT_EQ(bar->getWeakRefs()->getWeakCount(), 2);
+ wpBufferFull = true;
+ // Promotion races with that in visit3AndRemove.
+ // This may or may not succeed, but it shouldn't interfere with
+ // the concurrent one.
+ sp<Bar> sp1 = wp1.promote();
+ wpWaitFor(false); // Waits for other thread to drop strong pointer.
+ sp1 = nullptr;
+ // No strong pointers here.
+ sp1 = wp1.promote();
+ ASSERT_EQ(sp1.get(), nullptr) << "Dead wp promotion succeeded!";
+ }
+ t.join();
+ if (sched_setaffinity(0, sizeof(cpu_set_t), &origCpus) != 0) {
+ FAIL();
+ }
+ ASSERT_EQ(NITERS, deleteCount) << "Deletions missed!";
+ } // Otherwise this is slow and probably pointless on a uniprocessor.
+}
diff --git a/libutils/binder/SharedBuffer.cpp b/libutils/binder/SharedBuffer.cpp
new file mode 100644
index 0000000..3e703db
--- /dev/null
+++ b/libutils/binder/SharedBuffer.cpp
@@ -0,0 +1,140 @@
+/*
+ * Copyright (C) 2005 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.
+ */
+
+#define LOG_TAG "sharedbuffer"
+
+#include "SharedBuffer.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+#include <log/log.h>
+
+// ---------------------------------------------------------------------------
+
+namespace android {
+
+SharedBuffer* SharedBuffer::alloc(size_t size)
+{
+ // Don't overflow if the combined size of the buffer / header is larger than
+ // size_max.
+ LOG_ALWAYS_FATAL_IF((size >= (SIZE_MAX - sizeof(SharedBuffer))),
+ "Invalid buffer size %zu", size);
+
+ SharedBuffer* sb = static_cast<SharedBuffer *>(malloc(sizeof(SharedBuffer) + size));
+ if (sb) {
+ // Should be std::atomic_init(&sb->mRefs, 1);
+ // But that generates a warning with some compilers.
+ // The following is OK on Android-supported platforms.
+ sb->mRefs.store(1, std::memory_order_relaxed);
+ sb->mSize = size;
+ sb->mClientMetadata = 0;
+ }
+ return sb;
+}
+
+
+void SharedBuffer::dealloc(const SharedBuffer* released)
+{
+ free(const_cast<SharedBuffer*>(released));
+}
+
+SharedBuffer* SharedBuffer::edit() const
+{
+ if (onlyOwner()) {
+ return const_cast<SharedBuffer*>(this);
+ }
+ SharedBuffer* sb = alloc(mSize);
+ if (sb) {
+ memcpy(sb->data(), data(), size());
+ release();
+ }
+ return sb;
+}
+
+SharedBuffer* SharedBuffer::editResize(size_t newSize) const
+{
+ if (onlyOwner()) {
+ SharedBuffer* buf = const_cast<SharedBuffer*>(this);
+ if (buf->mSize == newSize) return buf;
+ // Don't overflow if the combined size of the new buffer / header is larger than
+ // size_max.
+ LOG_ALWAYS_FATAL_IF((newSize >= (SIZE_MAX - sizeof(SharedBuffer))),
+ "Invalid buffer size %zu", newSize);
+
+ buf = (SharedBuffer*)realloc(buf, sizeof(SharedBuffer) + newSize);
+ if (buf != nullptr) {
+ buf->mSize = newSize;
+ return buf;
+ }
+ }
+ SharedBuffer* sb = alloc(newSize);
+ if (sb) {
+ const size_t mySize = mSize;
+ memcpy(sb->data(), data(), newSize < mySize ? newSize : mySize);
+ release();
+ }
+ return sb;
+}
+
+SharedBuffer* SharedBuffer::attemptEdit() const
+{
+ if (onlyOwner()) {
+ return const_cast<SharedBuffer*>(this);
+ }
+ return nullptr;
+}
+
+SharedBuffer* SharedBuffer::reset(size_t new_size) const
+{
+ // cheap-o-reset.
+ SharedBuffer* sb = alloc(new_size);
+ if (sb) {
+ release();
+ }
+ return sb;
+}
+
+void SharedBuffer::acquire() const {
+ mRefs.fetch_add(1, std::memory_order_relaxed);
+}
+
+int32_t SharedBuffer::release(uint32_t flags) const
+{
+ const bool useDealloc = ((flags & eKeepStorage) == 0);
+ if (onlyOwner()) {
+ // Since we're the only owner, our reference count goes to zero.
+ mRefs.store(0, std::memory_order_relaxed);
+ if (useDealloc) {
+ dealloc(this);
+ }
+ // As the only owner, our previous reference count was 1.
+ return 1;
+ }
+ // There's multiple owners, we need to use an atomic decrement.
+ int32_t prevRefCount = mRefs.fetch_sub(1, std::memory_order_release);
+ if (prevRefCount == 1) {
+ // We're the last reference, we need the acquire fence.
+ atomic_thread_fence(std::memory_order_acquire);
+ if (useDealloc) {
+ dealloc(this);
+ }
+ }
+ return prevRefCount;
+}
+
+
+}; // namespace android
diff --git a/libutils/binder/SharedBuffer.h b/libutils/binder/SharedBuffer.h
new file mode 100644
index 0000000..476c842
--- /dev/null
+++ b/libutils/binder/SharedBuffer.h
@@ -0,0 +1,151 @@
+/*
+ * Copyright (C) 2005 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.
+ */
+
+/*
+ * DEPRECATED. DO NOT USE FOR NEW CODE.
+ */
+
+#ifndef ANDROID_SHARED_BUFFER_H
+#define ANDROID_SHARED_BUFFER_H
+
+#include <atomic>
+#include <stdint.h>
+#include <sys/types.h>
+
+// ---------------------------------------------------------------------------
+
+namespace android {
+
+class SharedBuffer
+{
+public:
+
+ /* flags to use with release() */
+ enum {
+ eKeepStorage = 0x00000001
+ };
+
+ /*! allocate a buffer of size 'size' and acquire() it.
+ * call release() to free it.
+ */
+ static SharedBuffer* alloc(size_t size);
+
+ /*! free the memory associated with the SharedBuffer.
+ * Fails if there are any users associated with this SharedBuffer.
+ * In other words, the buffer must have been release by all its
+ * users.
+ */
+ static void dealloc(const SharedBuffer* released);
+
+ //! access the data for read
+ inline const void* data() const;
+
+ //! access the data for read/write
+ inline void* data();
+
+ //! get size of the buffer
+ inline size_t size() const;
+
+ //! get back a SharedBuffer object from its data
+ static inline SharedBuffer* bufferFromData(void* data);
+
+ //! get back a SharedBuffer object from its data
+ static inline const SharedBuffer* bufferFromData(const void* data);
+
+ //! get the size of a SharedBuffer object from its data
+ static inline size_t sizeFromData(const void* data);
+
+ //! edit the buffer (get a writtable, or non-const, version of it)
+ SharedBuffer* edit() const;
+
+ //! edit the buffer, resizing if needed
+ SharedBuffer* editResize(size_t size) const;
+
+ //! like edit() but fails if a copy is required
+ SharedBuffer* attemptEdit() const;
+
+ //! resize and edit the buffer, loose it's content.
+ SharedBuffer* reset(size_t size) const;
+
+ //! acquire/release a reference on this buffer
+ void acquire() const;
+
+ /*! release a reference on this buffer, with the option of not
+ * freeing the memory associated with it if it was the last reference
+ * returns the previous reference count
+ */
+ int32_t release(uint32_t flags = 0) const;
+
+ //! returns wether or not we're the only owner
+ inline bool onlyOwner() const;
+
+
+private:
+ inline SharedBuffer() { }
+ inline ~SharedBuffer() { }
+ SharedBuffer(const SharedBuffer&);
+ SharedBuffer& operator = (const SharedBuffer&);
+
+ // Must be sized to preserve correct alignment.
+ mutable std::atomic<int32_t> mRefs;
+ size_t mSize;
+ uint32_t mReserved;
+public:
+ // mClientMetadata is reserved for client use. It is initialized to 0
+ // and the clients can do whatever they want with it. Note that this is
+ // placed last so that it is adjcent to the buffer allocated.
+ uint32_t mClientMetadata;
+};
+
+static_assert(sizeof(SharedBuffer) % 8 == 0
+ && (sizeof(size_t) > 4 || sizeof(SharedBuffer) == 16),
+ "SharedBuffer has unexpected size");
+
+// ---------------------------------------------------------------------------
+
+const void* SharedBuffer::data() const {
+ return this + 1;
+}
+
+void* SharedBuffer::data() {
+ return this + 1;
+}
+
+size_t SharedBuffer::size() const {
+ return mSize;
+}
+
+SharedBuffer* SharedBuffer::bufferFromData(void* data) {
+ return data ? static_cast<SharedBuffer *>(data)-1 : nullptr;
+}
+
+const SharedBuffer* SharedBuffer::bufferFromData(const void* data) {
+ return data ? static_cast<const SharedBuffer *>(data)-1 : nullptr;
+}
+
+size_t SharedBuffer::sizeFromData(const void* data) {
+ return data ? bufferFromData(data)->mSize : 0;
+}
+
+bool SharedBuffer::onlyOwner() const {
+ return (mRefs.load(std::memory_order_acquire) == 1);
+}
+
+} // namespace android
+
+// ---------------------------------------------------------------------------
+
+#endif // ANDROID_VECTOR_H
diff --git a/libutils/binder/SharedBuffer_test.cpp b/libutils/binder/SharedBuffer_test.cpp
new file mode 100644
index 0000000..1d6317f
--- /dev/null
+++ b/libutils/binder/SharedBuffer_test.cpp
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2015 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.
+ */
+
+#define __STDC_LIMIT_MACROS
+
+#include <gtest/gtest.h>
+
+#include <memory>
+#include <stdint.h>
+
+#include "SharedBuffer.h"
+
+extern "C" void __hwasan_init() __attribute__((weak));
+#define SKIP_WITH_HWASAN \
+ if (&__hwasan_init != 0) GTEST_SKIP()
+
+TEST(SharedBufferTest, alloc_death) {
+ EXPECT_DEATH(android::SharedBuffer::alloc(SIZE_MAX), "");
+ EXPECT_DEATH(android::SharedBuffer::alloc(SIZE_MAX - sizeof(android::SharedBuffer)), "");
+}
+
+TEST(SharedBufferTest, alloc_max) {
+ SKIP_WITH_HWASAN; // hwasan has a 2GiB allocation limit.
+
+ android::SharedBuffer* buf =
+ android::SharedBuffer::alloc(SIZE_MAX - sizeof(android::SharedBuffer) - 1);
+ if (buf != nullptr) {
+ EXPECT_NE(nullptr, buf->data());
+ buf->release();
+ }
+}
+
+TEST(SharedBufferTest, alloc_big) {
+ SKIP_WITH_HWASAN; // hwasan has a 2GiB allocation limit.
+
+ android::SharedBuffer* buf = android::SharedBuffer::alloc(SIZE_MAX / 2);
+ if (buf != nullptr) {
+ EXPECT_NE(nullptr, buf->data());
+ buf->release();
+ }
+}
+
+TEST(SharedBufferTest, alloc_zero_size) {
+ android::SharedBuffer* buf = android::SharedBuffer::alloc(0);
+ ASSERT_NE(nullptr, buf);
+ ASSERT_EQ(0U, buf->size());
+ buf->release();
+}
+
+TEST(SharedBufferTest, editResize_death) {
+ android::SharedBuffer* buf = android::SharedBuffer::alloc(10);
+ EXPECT_DEATH(buf->editResize(SIZE_MAX - sizeof(android::SharedBuffer)), "");
+ buf = android::SharedBuffer::alloc(10);
+ EXPECT_DEATH(buf->editResize(SIZE_MAX), "");
+}
+
+TEST(SharedBufferTest, editResize_null) {
+ // Big enough to fail, not big enough to abort.
+ SKIP_WITH_HWASAN; // hwasan has a 2GiB allocation limit.
+ android::SharedBuffer* buf = android::SharedBuffer::alloc(10);
+ android::SharedBuffer* buf2 = buf->editResize(SIZE_MAX / 2);
+ if (buf2 == nullptr) {
+ buf->release();
+ } else {
+ EXPECT_NE(nullptr, buf2->data());
+ buf2->release();
+ }
+}
+
+TEST(SharedBufferTest, editResize_zero_size) {
+ android::SharedBuffer* buf = android::SharedBuffer::alloc(10);
+ buf = buf->editResize(0);
+ ASSERT_EQ(0U, buf->size());
+ buf->release();
+}
diff --git a/libutils/binder/String16.cpp b/libutils/binder/String16.cpp
new file mode 100644
index 0000000..07a3d23
--- /dev/null
+++ b/libutils/binder/String16.cpp
@@ -0,0 +1,384 @@
+/*
+ * Copyright (C) 2005 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 <utils/String16.h>
+
+#include <log/log.h>
+
+#include <ctype.h>
+
+#include "SharedBuffer.h"
+
+namespace android {
+
+static const StaticString16 emptyString(u"");
+static inline char16_t* getEmptyString() {
+ return const_cast<char16_t*>(emptyString.c_str());
+}
+
+// ---------------------------------------------------------------------------
+
+void* String16::alloc(size_t size)
+{
+ SharedBuffer* buf = SharedBuffer::alloc(size);
+ buf->mClientMetadata = kIsSharedBufferAllocated;
+ return buf;
+}
+
+char16_t* String16::allocFromUTF8(const char* u8str, size_t u8len)
+{
+ if (u8len == 0) return getEmptyString();
+
+ const uint8_t* u8cur = (const uint8_t*) u8str;
+
+ const ssize_t u16len = utf8_to_utf16_length(u8cur, u8len);
+ if (u16len < 0) {
+ return getEmptyString();
+ }
+
+ SharedBuffer* buf = static_cast<SharedBuffer*>(alloc(sizeof(char16_t) * (u16len + 1)));
+ if (buf) {
+ u8cur = (const uint8_t*) u8str;
+ char16_t* u16str = (char16_t*)buf->data();
+
+ utf8_to_utf16(u8cur, u8len, u16str, ((size_t) u16len) + 1);
+
+ //printf("Created UTF-16 string from UTF-8 \"%s\":", in);
+ //printHexData(1, str, buf->size(), 16, 1);
+ //printf("\n");
+
+ return u16str;
+ }
+
+ return getEmptyString();
+}
+
+char16_t* String16::allocFromUTF16(const char16_t* u16str, size_t u16len) {
+ if (u16len >= SIZE_MAX / sizeof(char16_t)) {
+ android_errorWriteLog(0x534e4554, "73826242");
+ abort();
+ }
+
+ SharedBuffer* buf = static_cast<SharedBuffer*>(alloc((u16len + 1) * sizeof(char16_t)));
+ ALOG_ASSERT(buf, "Unable to allocate shared buffer");
+ if (buf) {
+ char16_t* str = (char16_t*)buf->data();
+ memcpy(str, u16str, u16len * sizeof(char16_t));
+ str[u16len] = 0;
+ return str;
+ }
+ return getEmptyString();
+}
+
+// ---------------------------------------------------------------------------
+
+String16::String16()
+ : mString(getEmptyString())
+{
+}
+
+String16::String16(const String16& o)
+ : mString(o.mString)
+{
+ acquire();
+}
+
+String16::String16(String16&& o) noexcept
+ : mString(o.mString)
+{
+ o.mString = getEmptyString();
+}
+
+String16::String16(const String16& o, size_t len, size_t begin)
+ : mString(getEmptyString())
+{
+ setTo(o, len, begin);
+}
+
+String16::String16(const char16_t* o) : mString(allocFromUTF16(o, strlen16(o))) {}
+
+String16::String16(const char16_t* o, size_t len) : mString(allocFromUTF16(o, len)) {}
+
+String16::String16(const String8& o) : mString(allocFromUTF8(o.c_str(), o.size())) {}
+
+String16::String16(const char* o)
+ : mString(allocFromUTF8(o, strlen(o)))
+{
+}
+
+String16::String16(const char* o, size_t len)
+ : mString(allocFromUTF8(o, len))
+{
+}
+
+String16::~String16()
+{
+ release();
+}
+
+String16& String16::operator=(String16&& other) noexcept {
+ release();
+ mString = other.mString;
+ other.mString = getEmptyString();
+ return *this;
+}
+
+size_t String16::size() const
+{
+ if (isStaticString()) {
+ return staticStringSize();
+ } else {
+ return SharedBuffer::sizeFromData(mString) / sizeof(char16_t) - 1;
+ }
+}
+
+void String16::setTo(const String16& other)
+{
+ release();
+ mString = other.mString;
+ acquire();
+}
+
+status_t String16::setTo(const String16& other, size_t len, size_t begin)
+{
+ const size_t N = other.size();
+ if (begin >= N) {
+ release();
+ mString = getEmptyString();
+ return OK;
+ }
+ if ((begin+len) > N) len = N-begin;
+ if (begin == 0 && len == N) {
+ setTo(other);
+ return OK;
+ }
+
+ if (&other == this) {
+ LOG_ALWAYS_FATAL("Not implemented");
+ }
+
+ return setTo(other.c_str() + begin, len);
+}
+
+status_t String16::setTo(const char16_t* other)
+{
+ return setTo(other, strlen16(other));
+}
+
+status_t String16::setTo(const char16_t* other, size_t len)
+{
+ if (len >= SIZE_MAX / sizeof(char16_t)) {
+ android_errorWriteLog(0x534e4554, "73826242");
+ abort();
+ }
+
+ SharedBuffer* buf = static_cast<SharedBuffer*>(editResize((len + 1) * sizeof(char16_t)));
+ if (buf) {
+ char16_t* str = (char16_t*)buf->data();
+ memmove(str, other, len*sizeof(char16_t));
+ str[len] = 0;
+ mString = str;
+ return OK;
+ }
+ return NO_MEMORY;
+}
+
+status_t String16::append(const String16& other) {
+ return append(other.c_str(), other.size());
+}
+
+status_t String16::append(const char16_t* chrs, size_t otherLen) {
+ const size_t myLen = size();
+
+ if (myLen == 0) return setTo(chrs, otherLen);
+
+ if (otherLen == 0) return OK;
+
+ size_t size = myLen;
+ if (__builtin_add_overflow(size, otherLen, &size) ||
+ __builtin_add_overflow(size, 1, &size) ||
+ __builtin_mul_overflow(size, sizeof(char16_t), &size)) return NO_MEMORY;
+
+ SharedBuffer* buf = static_cast<SharedBuffer*>(editResize(size));
+ if (!buf) return NO_MEMORY;
+
+ char16_t* str = static_cast<char16_t*>(buf->data());
+ memcpy(str + myLen, chrs, otherLen * sizeof(char16_t));
+ str[myLen + otherLen] = 0;
+ mString = str;
+ return OK;
+}
+
+status_t String16::insert(size_t pos, const char16_t* chrs) {
+ return insert(pos, chrs, strlen16(chrs));
+}
+
+status_t String16::insert(size_t pos, const char16_t* chrs, size_t otherLen) {
+ const size_t myLen = size();
+
+ if (myLen == 0) return setTo(chrs, otherLen);
+
+ if (otherLen == 0) return OK;
+
+ if (pos > myLen) pos = myLen;
+
+ size_t size = myLen;
+ if (__builtin_add_overflow(size, otherLen, &size) ||
+ __builtin_add_overflow(size, 1, &size) ||
+ __builtin_mul_overflow(size, sizeof(char16_t), &size)) return NO_MEMORY;
+
+ SharedBuffer* buf = static_cast<SharedBuffer*>(editResize(size));
+ if (!buf) return NO_MEMORY;
+
+ char16_t* str = static_cast<char16_t*>(buf->data());
+ if (pos < myLen) memmove(str + pos + otherLen, str + pos, (myLen - pos) * sizeof(char16_t));
+ memcpy(str + pos, chrs, otherLen * sizeof(char16_t));
+ str[myLen + otherLen] = 0;
+ mString = str;
+ return OK;
+}
+
+ssize_t String16::findFirst(char16_t c) const
+{
+ const char16_t* str = string();
+ const char16_t* p = str;
+ const char16_t* e = p + size();
+ while (p < e) {
+ if (*p == c) {
+ return p-str;
+ }
+ p++;
+ }
+ return -1;
+}
+
+ssize_t String16::findLast(char16_t c) const
+{
+ const char16_t* str = string();
+ const char16_t* p = str;
+ const char16_t* e = p + size();
+ while (p < e) {
+ e--;
+ if (*e == c) {
+ return e-str;
+ }
+ }
+ return -1;
+}
+
+bool String16::startsWith(const String16& prefix) const
+{
+ const size_t ps = prefix.size();
+ if (ps > size()) return false;
+ return strzcmp16(mString, ps, prefix.c_str(), ps) == 0;
+}
+
+bool String16::startsWith(const char16_t* prefix) const
+{
+ const size_t ps = strlen16(prefix);
+ if (ps > size()) return false;
+ return strncmp16(mString, prefix, ps) == 0;
+}
+
+bool String16::contains(const char16_t* chrs) const
+{
+ return strstr16(mString, chrs) != nullptr;
+}
+
+void* String16::edit() {
+ SharedBuffer* buf;
+ if (isStaticString()) {
+ buf = static_cast<SharedBuffer*>(alloc((size() + 1) * sizeof(char16_t)));
+ if (buf) {
+ memcpy(buf->data(), mString, (size() + 1) * sizeof(char16_t));
+ }
+ } else {
+ buf = SharedBuffer::bufferFromData(mString)->edit();
+ buf->mClientMetadata = kIsSharedBufferAllocated;
+ }
+ return buf;
+}
+
+void* String16::editResize(size_t newSize) {
+ SharedBuffer* buf;
+ if (isStaticString()) {
+ size_t copySize = (size() + 1) * sizeof(char16_t);
+ if (newSize < copySize) {
+ copySize = newSize;
+ }
+ buf = static_cast<SharedBuffer*>(alloc(newSize));
+ if (buf) {
+ memcpy(buf->data(), mString, copySize);
+ }
+ } else {
+ buf = SharedBuffer::bufferFromData(mString)->editResize(newSize);
+ buf->mClientMetadata = kIsSharedBufferAllocated;
+ }
+ return buf;
+}
+
+void String16::acquire()
+{
+ if (!isStaticString()) {
+ SharedBuffer::bufferFromData(mString)->acquire();
+ }
+}
+
+void String16::release()
+{
+ if (!isStaticString()) {
+ SharedBuffer::bufferFromData(mString)->release();
+ }
+}
+
+bool String16::isStaticString() const {
+ // See String16.h for notes on the memory layout of String16::StaticData and
+ // SharedBuffer.
+ static_assert(sizeof(SharedBuffer) - offsetof(SharedBuffer, mClientMetadata) == 4);
+ const uint32_t* p = reinterpret_cast<const uint32_t*>(mString);
+ return (*(p - 1) & kIsSharedBufferAllocated) == 0;
+}
+
+size_t String16::staticStringSize() const {
+ // See String16.h for notes on the memory layout of String16::StaticData and
+ // SharedBuffer.
+ static_assert(sizeof(SharedBuffer) - offsetof(SharedBuffer, mClientMetadata) == 4);
+ const uint32_t* p = reinterpret_cast<const uint32_t*>(mString);
+ return static_cast<size_t>(*(p - 1));
+}
+
+status_t String16::replaceAll(char16_t replaceThis, char16_t withThis)
+{
+ const size_t N = size();
+ const char16_t* str = string();
+ char16_t* edited = nullptr;
+ for (size_t i=0; i<N; i++) {
+ if (str[i] == replaceThis) {
+ if (!edited) {
+ SharedBuffer* buf = static_cast<SharedBuffer*>(edit());
+ if (!buf) {
+ return NO_MEMORY;
+ }
+ edited = (char16_t*)buf->data();
+ mString = str = edited;
+ }
+ edited[i] = withThis;
+ }
+ }
+ return OK;
+}
+
+}; // namespace android
diff --git a/libutils/binder/String16_fuzz.cpp b/libutils/binder/String16_fuzz.cpp
new file mode 100644
index 0000000..8f9781b
--- /dev/null
+++ b/libutils/binder/String16_fuzz.cpp
@@ -0,0 +1,111 @@
+/*
+ * Copyright 2020 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 <functional>
+#include <iostream>
+#include <vector>
+
+#include "fuzzer/FuzzedDataProvider.h"
+#include "utils/String16.h"
+static constexpr int MAX_STRING_BYTES = 256;
+static constexpr uint8_t MAX_OPERATIONS = 50;
+
+std::vector<std::function<void(FuzzedDataProvider&, android::String16, android::String16)>>
+ operations = {
+
+ // Bytes and size
+ ([](FuzzedDataProvider&, android::String16 str1, android::String16) -> void {
+ str1.c_str();
+ }),
+ ([](FuzzedDataProvider&, android::String16 str1, android::String16) -> void {
+ str1.isStaticString();
+ }),
+ ([](FuzzedDataProvider&, android::String16 str1, android::String16) -> void {
+ str1.size();
+ }),
+
+ // Comparison
+ ([](FuzzedDataProvider&, android::String16 str1, android::String16 str2) -> void {
+ str1.startsWith(str2);
+ }),
+ ([](FuzzedDataProvider&, android::String16 str1, android::String16 str2) -> void {
+ str1.contains(str2.c_str());
+ }),
+ ([](FuzzedDataProvider&, android::String16 str1, android::String16 str2) -> void {
+ str1.compare(str2);
+ }),
+
+ // Append and format
+ ([](FuzzedDataProvider&, android::String16 str1, android::String16 str2) -> void {
+ str1.append(str2);
+ }),
+ ([](FuzzedDataProvider& dataProvider, android::String16 str1,
+ android::String16 str2) -> void {
+ int pos = dataProvider.ConsumeIntegralInRange<int>(0, str1.size());
+ str1.insert(pos, str2.c_str());
+ }),
+
+ // Find and replace operations
+ ([](FuzzedDataProvider& dataProvider, android::String16 str1,
+ android::String16) -> void {
+ char16_t findChar = dataProvider.ConsumeIntegral<char16_t>();
+ str1.findFirst(findChar);
+ }),
+ ([](FuzzedDataProvider& dataProvider, android::String16 str1,
+ android::String16) -> void {
+ char16_t findChar = dataProvider.ConsumeIntegral<char16_t>();
+ str1.findLast(findChar);
+ }),
+ ([](FuzzedDataProvider& dataProvider, android::String16 str1,
+ android::String16) -> void {
+ char16_t findChar = dataProvider.ConsumeIntegral<char16_t>();
+ char16_t replaceChar = dataProvider.ConsumeIntegral<char16_t>();
+ str1.replaceAll(findChar, replaceChar);
+ }),
+};
+
+void callFunc(uint8_t index, FuzzedDataProvider& dataProvider, android::String16 str1,
+ android::String16 str2) {
+ operations[index](dataProvider, str1, str2);
+}
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+ FuzzedDataProvider dataProvider(data, size);
+ // We're generating two char vectors.
+ // First, generate lengths.
+ const size_t kVecOneLen = dataProvider.ConsumeIntegralInRange<size_t>(1, MAX_STRING_BYTES);
+ const size_t kVecTwoLen = dataProvider.ConsumeIntegralInRange<size_t>(1, MAX_STRING_BYTES);
+
+ // Next, populate the vectors
+ std::vector<char> vec = dataProvider.ConsumeBytesWithTerminator<char>(kVecOneLen);
+ std::vector<char> vec_two = dataProvider.ConsumeBytesWithTerminator<char>(kVecTwoLen);
+
+ // Get pointers to their data
+ char* char_one = vec.data();
+ char* char_two = vec_two.data();
+
+ // Create UTF16 representations
+ android::String16 str_one_utf16 = android::String16(char_one);
+ android::String16 str_two_utf16 = android::String16(char_two);
+
+ // Run operations against strings
+ int opsRun = 0;
+ while (dataProvider.remaining_bytes() > 0 && opsRun++ < MAX_OPERATIONS) {
+ uint8_t op = dataProvider.ConsumeIntegralInRange<uint8_t>(0, operations.size() - 1);
+ callFunc(op, dataProvider, str_one_utf16, str_two_utf16);
+ }
+
+ return 0;
+}
diff --git a/libutils/binder/String16_test.cpp b/libutils/binder/String16_test.cpp
new file mode 100644
index 0000000..6f4642e
--- /dev/null
+++ b/libutils/binder/String16_test.cpp
@@ -0,0 +1,259 @@
+/*
+ * 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 <utils/String16.h>
+#include <utils/String8.h>
+
+#include <gtest/gtest.h>
+
+using namespace android;
+
+::testing::AssertionResult Char16_tStringEquals(const char16_t* a, const char16_t* b) {
+ if (strcmp16(a, b) != 0) {
+ return ::testing::AssertionFailure()
+ << "\"" << String8(a).c_str() << "\" not equal to \"" << String8(b).c_str() << "\"";
+ }
+ return ::testing::AssertionSuccess();
+}
+
+#define EXPECT_STR16EQ(a, b) EXPECT_TRUE(Char16_tStringEquals(a, b))
+
+TEST(String16Test, FromChar16_t) {
+ String16 tmp(u"Verify me");
+ EXPECT_STR16EQ(u"Verify me", tmp.c_str());
+}
+
+TEST(String16Test, FromChar16_tSized) {
+ String16 tmp(u"Verify me", 7);
+ EXPECT_STR16EQ(u"Verify ", tmp.c_str());
+}
+
+TEST(String16Test, FromChar) {
+ String16 tmp("Verify me");
+ EXPECT_STR16EQ(u"Verify me", tmp.c_str());
+}
+
+TEST(String16Test, FromCharSized) {
+ String16 tmp("Verify me", 7);
+ EXPECT_STR16EQ(u"Verify ", tmp.c_str());
+}
+
+TEST(String16Test, Copy) {
+ String16 tmp("Verify me");
+ String16 another = tmp;
+ EXPECT_STR16EQ(u"Verify me", tmp.c_str());
+ EXPECT_STR16EQ(u"Verify me", another.c_str());
+}
+
+TEST(String16Test, CopyAssign) {
+ String16 tmp("Verify me");
+ String16 another;
+ another = tmp;
+ EXPECT_STR16EQ(u"Verify me", tmp.c_str());
+ EXPECT_STR16EQ(u"Verify me", another.c_str());
+}
+
+TEST(String16Test, Move) {
+ String16 tmp("Verify me");
+ String16 another(std::move(tmp));
+ EXPECT_STR16EQ(u"Verify me", another.c_str());
+}
+
+TEST(String16Test, MoveAssign) {
+ String16 tmp("Verify me");
+ String16 another;
+ another = std::move(tmp);
+ EXPECT_STR16EQ(u"Verify me", another.c_str());
+}
+
+TEST(String16Test, Size) {
+ String16 tmp("Verify me");
+ EXPECT_EQ(9U, tmp.size());
+}
+
+TEST(String16Test, setTo) {
+ String16 tmp("Verify me");
+ tmp.setTo(u"New content");
+ EXPECT_EQ(11U, tmp.size());
+ EXPECT_STR16EQ(u"New content", tmp.c_str());
+}
+
+TEST(String16Test, Append) {
+ String16 tmp("Verify me");
+ tmp.append(String16("Hello"));
+ EXPECT_EQ(14U, tmp.size());
+ EXPECT_STR16EQ(u"Verify meHello", tmp.c_str());
+}
+
+TEST(String16Test, Insert) {
+ String16 tmp("Verify me");
+ tmp.insert(6, u"Insert");
+ EXPECT_EQ(15U, tmp.size());
+ EXPECT_STR16EQ(u"VerifyInsert me", tmp.c_str());
+}
+
+TEST(String16Test, ReplaceAll) {
+ String16 tmp("Verify verify Verify");
+ tmp.replaceAll(u'r', u'!');
+ EXPECT_STR16EQ(u"Ve!ify ve!ify Ve!ify", tmp.c_str());
+}
+
+TEST(String16Test, Compare) {
+ String16 tmp("Verify me");
+ EXPECT_EQ(String16(u"Verify me"), tmp);
+}
+
+TEST(String16Test, StaticString) {
+ String16 nonStaticString("NonStatic");
+ StaticString16 staticString(u"Static");
+
+ EXPECT_TRUE(staticString.isStaticString());
+ EXPECT_FALSE(nonStaticString.isStaticString());
+}
+
+TEST(String16Test, StaticStringCopy) {
+ StaticString16 tmp(u"Verify me");
+ String16 another = tmp;
+ EXPECT_STR16EQ(u"Verify me", tmp.c_str());
+ EXPECT_STR16EQ(u"Verify me", another.c_str());
+ EXPECT_TRUE(tmp.isStaticString());
+ EXPECT_TRUE(another.isStaticString());
+}
+
+TEST(String16Test, StaticStringMove) {
+ StaticString16 tmp(u"Verify me");
+ String16 another(std::move(tmp));
+ EXPECT_STR16EQ(u"Verify me", another.c_str());
+ EXPECT_TRUE(another.isStaticString());
+}
+
+TEST(String16Test, StaticStringSize) {
+ StaticString16 tmp(u"Verify me");
+ EXPECT_EQ(9U, tmp.size());
+}
+
+TEST(String16Test, StaticStringSetTo) {
+ StaticString16 tmp(u"Verify me");
+ tmp.setTo(u"New content");
+ EXPECT_EQ(11U, tmp.size());
+ EXPECT_STR16EQ(u"New content", tmp);
+ EXPECT_FALSE(tmp.isStaticString());
+}
+
+TEST(String16Test, StaticStringAppend) {
+ StaticString16 tmp(u"Verify me");
+ tmp.append(String16("Hello"));
+ EXPECT_EQ(14U, tmp.size());
+ EXPECT_STR16EQ(u"Verify meHello", tmp.c_str());
+ EXPECT_FALSE(tmp.isStaticString());
+}
+
+TEST(String16Test, StaticStringInsert) {
+ StaticString16 tmp(u"Verify me");
+ tmp.insert(6, u"Insert");
+ EXPECT_EQ(15U, tmp.size());
+ EXPECT_STR16EQ(u"VerifyInsert me", tmp.c_str());
+ EXPECT_FALSE(tmp.isStaticString());
+}
+
+TEST(String16Test, StaticStringReplaceAll) {
+ StaticString16 tmp(u"Verify verify Verify");
+ tmp.replaceAll(u'r', u'!');
+ EXPECT_STR16EQ(u"Ve!ify ve!ify Ve!ify", tmp.c_str());
+ EXPECT_FALSE(tmp.isStaticString());
+}
+
+TEST(String16Test, StaticStringCompare) {
+ StaticString16 tmp(u"Verify me");
+ EXPECT_EQ(String16(u"Verify me"), tmp);
+}
+
+TEST(String16Test, StringSetToStaticString) {
+ StaticString16 tmp(u"Verify me");
+ String16 another(u"nonstatic");
+ another = tmp;
+ EXPECT_STR16EQ(u"Verify me", tmp.c_str());
+ EXPECT_STR16EQ(u"Verify me", another.c_str());
+}
+
+TEST(String16Test, StringCopyAssignFromStaticString) {
+ StaticString16 tmp(u"Verify me");
+ String16 another(u"nonstatic");
+ another = tmp;
+ EXPECT_STR16EQ(u"Verify me", another.c_str());
+ EXPECT_TRUE(another.isStaticString());
+ EXPECT_STR16EQ(u"Verify me", tmp.c_str());
+ EXPECT_TRUE(tmp.isStaticString());
+}
+
+TEST(String16Test, StringMoveAssignFromStaticString) {
+ StaticString16 tmp(u"Verify me");
+ String16 another(u"nonstatic");
+ another = std::move(tmp);
+ EXPECT_STR16EQ(u"Verify me", another.c_str());
+ EXPECT_TRUE(another.isStaticString());
+}
+
+TEST(String16Test, EmptyStringIsStatic) {
+ String16 tmp("");
+ EXPECT_TRUE(tmp.isStaticString());
+}
+
+TEST(String16Test, OverreadUtf8Conversion) {
+ char tmp[] = {'a', static_cast<char>(0xe0), '\0'};
+ String16 another(tmp);
+ EXPECT_TRUE(another.size() == 0);
+}
+
+TEST(String16Test, ValidUtf8Conversion) {
+ String16 another("abcdef");
+ EXPECT_EQ(6U, another.size());
+ EXPECT_STR16EQ(another.c_str(), u"abcdef");
+}
+
+TEST(String16Test, append) {
+ String16 s;
+ EXPECT_EQ(OK, s.append(String16(u"foo")));
+ EXPECT_STR16EQ(u"foo", s.c_str());
+ EXPECT_EQ(OK, s.append(String16(u"bar")));
+ EXPECT_STR16EQ(u"foobar", s.c_str());
+ EXPECT_EQ(OK, s.append(u"baz", 0));
+ EXPECT_STR16EQ(u"foobar", s.c_str());
+ EXPECT_EQ(NO_MEMORY, s.append(u"baz", SIZE_MAX));
+ EXPECT_STR16EQ(u"foobar", s.c_str());
+}
+
+TEST(String16Test, insert) {
+ String16 s;
+
+ // Inserting into the empty string inserts at the start.
+ EXPECT_EQ(OK, s.insert(123, u"foo"));
+ EXPECT_STR16EQ(u"foo", s.c_str());
+
+ // Inserting zero characters at any position is okay, but won't expand the string.
+ EXPECT_EQ(OK, s.insert(123, u"foo", 0));
+ EXPECT_STR16EQ(u"foo", s.c_str());
+
+ // Inserting past the end of a non-empty string appends.
+ EXPECT_EQ(OK, s.insert(123, u"bar"));
+ EXPECT_STR16EQ(u"foobar", s.c_str());
+
+ EXPECT_EQ(OK, s.insert(3, u"!"));
+ EXPECT_STR16EQ(u"foo!bar", s.c_str());
+
+ EXPECT_EQ(NO_MEMORY, s.insert(3, u"", SIZE_MAX));
+ EXPECT_STR16EQ(u"foo!bar", s.c_str());
+}
diff --git a/libutils/binder/String8.cpp b/libutils/binder/String8.cpp
new file mode 100644
index 0000000..6a75484
--- /dev/null
+++ b/libutils/binder/String8.cpp
@@ -0,0 +1,479 @@
+/*
+ * Copyright (C) 2005 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.
+ */
+
+#define __STDC_LIMIT_MACROS
+#include <stdint.h>
+
+#include <utils/String8.h>
+
+#include <utils/Compat.h>
+#include <log/log.h>
+#include <utils/String16.h>
+
+#include <ctype.h>
+
+#include <limits>
+#include <string>
+
+#include "SharedBuffer.h"
+
+/*
+ * Functions outside android is below the namespace android, since they use
+ * functions and constants in android namespace.
+ */
+
+// ---------------------------------------------------------------------------
+
+namespace android {
+
+static inline char* getEmptyString() {
+ static SharedBuffer* gEmptyStringBuf = [] {
+ SharedBuffer* buf = SharedBuffer::alloc(1);
+ char* str = static_cast<char*>(buf->data());
+ *str = 0;
+ return buf;
+ }();
+
+ gEmptyStringBuf->acquire();
+ return static_cast<char*>(gEmptyStringBuf->data());
+}
+
+// ---------------------------------------------------------------------------
+
+static char* allocFromUTF8(const char* in, size_t len)
+{
+ if (len > 0) {
+ if (len == SIZE_MAX) {
+ return nullptr;
+ }
+ SharedBuffer* buf = SharedBuffer::alloc(len+1);
+ ALOG_ASSERT(buf, "Unable to allocate shared buffer");
+ if (buf) {
+ char* str = (char*)buf->data();
+ memcpy(str, in, len);
+ str[len] = 0;
+ return str;
+ }
+ return nullptr;
+ }
+
+ return getEmptyString();
+}
+
+static char* allocFromUTF16(const char16_t* in, size_t len)
+{
+ if (len == 0) return getEmptyString();
+
+ // Allow for closing '\0'
+ const ssize_t resultStrLen = utf16_to_utf8_length(in, len) + 1;
+ if (resultStrLen < 1) {
+ return getEmptyString();
+ }
+
+ SharedBuffer* buf = SharedBuffer::alloc(resultStrLen);
+ ALOG_ASSERT(buf, "Unable to allocate shared buffer");
+ if (!buf) {
+ return getEmptyString();
+ }
+
+ char* resultStr = (char*)buf->data();
+ utf16_to_utf8(in, len, resultStr, resultStrLen);
+ return resultStr;
+}
+
+static char* allocFromUTF32(const char32_t* in, size_t len)
+{
+ if (len == 0) {
+ return getEmptyString();
+ }
+
+ const ssize_t resultStrLen = utf32_to_utf8_length(in, len) + 1;
+ if (resultStrLen < 1) {
+ return getEmptyString();
+ }
+
+ SharedBuffer* buf = SharedBuffer::alloc(resultStrLen);
+ ALOG_ASSERT(buf, "Unable to allocate shared buffer");
+ if (!buf) {
+ return getEmptyString();
+ }
+
+ char* resultStr = (char*) buf->data();
+ utf32_to_utf8(in, len, resultStr, resultStrLen);
+
+ return resultStr;
+}
+
+// ---------------------------------------------------------------------------
+
+String8::String8()
+ : mString(getEmptyString())
+{
+}
+
+String8::String8(const String8& o)
+ : mString(o.mString)
+{
+ SharedBuffer::bufferFromData(mString)->acquire();
+}
+
+String8::String8(const char* o)
+ : mString(allocFromUTF8(o, strlen(o)))
+{
+ if (mString == nullptr) {
+ mString = getEmptyString();
+ }
+}
+
+String8::String8(const char* o, size_t len)
+ : mString(allocFromUTF8(o, len))
+{
+ if (mString == nullptr) {
+ mString = getEmptyString();
+ }
+}
+
+String8::String8(const String16& o) : mString(allocFromUTF16(o.c_str(), o.size())) {}
+
+String8::String8(const char16_t* o)
+ : mString(allocFromUTF16(o, strlen16(o)))
+{
+}
+
+String8::String8(const char16_t* o, size_t len)
+ : mString(allocFromUTF16(o, len))
+{
+}
+
+String8::String8(const char32_t* o)
+ : mString(allocFromUTF32(o, std::char_traits<char32_t>::length(o))) {}
+
+String8::String8(const char32_t* o, size_t len)
+ : mString(allocFromUTF32(o, len))
+{
+}
+
+String8::~String8()
+{
+ SharedBuffer::bufferFromData(mString)->release();
+}
+
+size_t String8::length() const
+{
+ return SharedBuffer::sizeFromData(mString)-1;
+}
+
+String8 String8::format(const char* fmt, ...)
+{
+ va_list args;
+ va_start(args, fmt);
+
+ String8 result(formatV(fmt, args));
+
+ va_end(args);
+ return result;
+}
+
+String8 String8::formatV(const char* fmt, va_list args)
+{
+ String8 result;
+ result.appendFormatV(fmt, args);
+ return result;
+}
+
+void String8::clear() {
+ SharedBuffer::bufferFromData(mString)->release();
+ mString = getEmptyString();
+}
+
+void String8::setTo(const String8& other)
+{
+ SharedBuffer::bufferFromData(other.mString)->acquire();
+ SharedBuffer::bufferFromData(mString)->release();
+ mString = other.mString;
+}
+
+status_t String8::setTo(const char* other)
+{
+ const char *newString = allocFromUTF8(other, strlen(other));
+ SharedBuffer::bufferFromData(mString)->release();
+ mString = newString;
+ if (mString) return OK;
+
+ mString = getEmptyString();
+ return NO_MEMORY;
+}
+
+status_t String8::setTo(const char* other, size_t len)
+{
+ const char *newString = allocFromUTF8(other, len);
+ SharedBuffer::bufferFromData(mString)->release();
+ mString = newString;
+ if (mString) return OK;
+
+ mString = getEmptyString();
+ return NO_MEMORY;
+}
+
+status_t String8::setTo(const char16_t* other, size_t len)
+{
+ const char *newString = allocFromUTF16(other, len);
+ SharedBuffer::bufferFromData(mString)->release();
+ mString = newString;
+ if (mString) return OK;
+
+ mString = getEmptyString();
+ return NO_MEMORY;
+}
+
+status_t String8::setTo(const char32_t* other, size_t len)
+{
+ const char *newString = allocFromUTF32(other, len);
+ SharedBuffer::bufferFromData(mString)->release();
+ mString = newString;
+ if (mString) return OK;
+
+ mString = getEmptyString();
+ return NO_MEMORY;
+}
+
+status_t String8::append(const String8& other)
+{
+ const size_t otherLen = other.bytes();
+ if (bytes() == 0) {
+ setTo(other);
+ return OK;
+ } else if (otherLen == 0) {
+ return OK;
+ }
+
+ return real_append(other.c_str(), otherLen);
+}
+
+status_t String8::append(const char* other)
+{
+ return append(other, strlen(other));
+}
+
+status_t String8::append(const char* other, size_t otherLen)
+{
+ if (bytes() == 0) {
+ return setTo(other, otherLen);
+ } else if (otherLen == 0) {
+ return OK;
+ }
+
+ return real_append(other, otherLen);
+}
+
+status_t String8::appendFormat(const char* fmt, ...)
+{
+ va_list args;
+ va_start(args, fmt);
+
+ status_t result = appendFormatV(fmt, args);
+
+ va_end(args);
+ return result;
+}
+
+status_t String8::appendFormatV(const char* fmt, va_list args)
+{
+ int n, result = OK;
+ va_list tmp_args;
+
+ /* args is undefined after vsnprintf.
+ * So we need a copy here to avoid the
+ * second vsnprintf access undefined args.
+ */
+ va_copy(tmp_args, args);
+ n = vsnprintf(nullptr, 0, fmt, tmp_args);
+ va_end(tmp_args);
+
+ if (n < 0) return UNKNOWN_ERROR;
+
+ if (n > 0) {
+ size_t oldLength = length();
+ if (static_cast<size_t>(n) > std::numeric_limits<size_t>::max() - 1 ||
+ oldLength > std::numeric_limits<size_t>::max() - n - 1) {
+ return NO_MEMORY;
+ }
+ char* buf = lockBuffer(oldLength + n);
+ if (buf) {
+ vsnprintf(buf + oldLength, n + 1, fmt, args);
+ } else {
+ result = NO_MEMORY;
+ }
+ }
+ return result;
+}
+
+status_t String8::real_append(const char* other, size_t otherLen) {
+ const size_t myLen = bytes();
+
+ SharedBuffer* buf;
+ size_t newLen;
+ if (__builtin_add_overflow(myLen, otherLen, &newLen) ||
+ __builtin_add_overflow(newLen, 1, &newLen) ||
+ (buf = SharedBuffer::bufferFromData(mString)->editResize(newLen)) == nullptr) {
+ return NO_MEMORY;
+ }
+
+ char* str = (char*)buf->data();
+ mString = str;
+ str += myLen;
+ memcpy(str, other, otherLen);
+ str[otherLen] = '\0';
+ return OK;
+}
+
+char* String8::lockBuffer(size_t size)
+{
+ SharedBuffer* buf = SharedBuffer::bufferFromData(mString)
+ ->editResize(size+1);
+ if (buf) {
+ char* str = (char*)buf->data();
+ mString = str;
+ return str;
+ }
+ return nullptr;
+}
+
+void String8::unlockBuffer()
+{
+ unlockBuffer(strlen(mString));
+}
+
+status_t String8::unlockBuffer(size_t size)
+{
+ if (size != this->size()) {
+ SharedBuffer* buf = SharedBuffer::bufferFromData(mString)
+ ->editResize(size+1);
+ if (! buf) {
+ return NO_MEMORY;
+ }
+
+ char* str = (char*)buf->data();
+ str[size] = 0;
+ mString = str;
+ }
+
+ return OK;
+}
+
+ssize_t String8::find(const char* other, size_t start) const
+{
+ size_t len = size();
+ if (start >= len) {
+ return -1;
+ }
+ const char* s = mString+start;
+ const char* p = strstr(s, other);
+ return p ? p-mString : -1;
+}
+
+bool String8::removeAll(const char* other) {
+ ALOG_ASSERT(other, "String8::removeAll() requires a non-NULL string");
+
+ if (*other == '\0')
+ return true;
+
+ ssize_t index = find(other);
+ if (index < 0) return false;
+
+ char* buf = lockBuffer(size());
+ if (!buf) return false; // out of memory
+
+ size_t skip = strlen(other);
+ size_t len = size();
+ size_t tail = index;
+ while (size_t(index) < len) {
+ ssize_t next = find(other, index + skip);
+ if (next < 0) {
+ next = len;
+ }
+
+ memmove(buf + tail, buf + index + skip, next - index - skip);
+ tail += next - index - skip;
+ index = next;
+ }
+ unlockBuffer(tail);
+ return true;
+}
+
+void String8::toLower()
+{
+ const size_t length = size();
+ if (length == 0) return;
+
+ char* buf = lockBuffer(length);
+ for (size_t i = length; i > 0; --i) {
+ *buf = static_cast<char>(tolower(*buf));
+ buf++;
+ }
+ unlockBuffer(length);
+}
+
+// ---------------------------------------------------------------------------
+// Path functions
+
+String8 String8::getPathDir(void) const
+{
+ const char* cp;
+ const char*const str = mString;
+
+ cp = strrchr(str, OS_PATH_SEPARATOR);
+ if (cp == nullptr)
+ return String8("");
+ else
+ return String8(str, cp - str);
+}
+
+/*
+ * Helper function for finding the start of an extension in a pathname.
+ *
+ * Returns a pointer inside mString, or NULL if no extension was found.
+ */
+static const char* find_extension(const char* str) {
+ const char* lastSlash;
+ const char* lastDot;
+
+ // only look at the filename
+ lastSlash = strrchr(str, OS_PATH_SEPARATOR);
+ if (lastSlash == nullptr)
+ lastSlash = str;
+ else
+ lastSlash++;
+
+ // find the last dot
+ lastDot = strrchr(lastSlash, '.');
+ if (lastDot == nullptr)
+ return nullptr;
+
+ // looks good, ship it
+ return lastDot;
+}
+
+String8 String8::getPathExtension(void) const
+{
+ auto ext = find_extension(mString);
+ if (ext != nullptr)
+ return String8(ext);
+ else
+ return String8("");
+}
+
+}; // namespace android
diff --git a/libutils/binder/String8_fuzz.cpp b/libutils/binder/String8_fuzz.cpp
new file mode 100644
index 0000000..cbce050
--- /dev/null
+++ b/libutils/binder/String8_fuzz.cpp
@@ -0,0 +1,204 @@
+/*
+ * Copyright 2020 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 <functional>
+#include <iostream>
+#include <memory>
+
+#include "FuzzFormatTypes.h"
+#include "fuzzer/FuzzedDataProvider.h"
+#include "utils/String8.h"
+
+static constexpr int MAX_STRING_BYTES = 256;
+static constexpr uint8_t MAX_OPERATIONS = 50;
+// Interestingly, 2147483614 (INT32_MAX - 33) seems to be the max value that is handled for format
+// flags. Unfortunately we need to use a smaller value so we avoid consuming too much memory.
+
+void fuzzFormat(FuzzedDataProvider* dataProvider, android::String8* str1, bool shouldAppend);
+std::vector<std::function<void(FuzzedDataProvider*, android::String8*, android::String8*)>>
+ operations = {
+ // Bytes and size
+ [](FuzzedDataProvider*, android::String8* str1, android::String8*) -> void {
+ str1->bytes();
+ },
+ [](FuzzedDataProvider*, android::String8* str1, android::String8*) -> void {
+ str1->empty();
+ },
+ [](FuzzedDataProvider*, android::String8* str1, android::String8*) -> void {
+ str1->length();
+ },
+
+ // Casing
+ [](FuzzedDataProvider*, android::String8* str1, android::String8*) -> void {
+ str1->toLower();
+ },
+ [](FuzzedDataProvider*, android::String8* str1, android::String8* str2) -> void {
+ if (str2->size() == 0) return;
+
+ str1->removeAll(str2->c_str());
+ },
+ [](FuzzedDataProvider*, android::String8* str1, android::String8* str2) -> void {
+ const android::String8& constRef(*str2);
+ str1->compare(constRef);
+ },
+
+ // Append and format
+ [](FuzzedDataProvider*, android::String8* str1, android::String8* str2) -> void {
+ str1->append(str2->c_str());
+ },
+ [](FuzzedDataProvider* dataProvider, android::String8* str1, android::String8*)
+ -> void { fuzzFormat(dataProvider, str1, dataProvider->ConsumeBool()); },
+
+ // Find operation
+ [](FuzzedDataProvider* dataProvider, android::String8* str1,
+ android::String8* str2) -> void {
+ // We need to get a value from our fuzzer here.
+ int start_index = dataProvider->ConsumeIntegralInRange<int>(0, str1->size());
+ str1->find(str2->c_str(), start_index);
+ },
+};
+
+void fuzzFormat(FuzzedDataProvider* dataProvider, android::String8* str1, bool shouldAppend) {
+ FormatChar formatType = dataProvider->ConsumeEnum<FormatChar>();
+
+ std::string formatString("%");
+ // Width specifier
+ if (dataProvider->ConsumeBool()) {
+ // Left pad with zeroes
+ if (dataProvider->ConsumeBool()) {
+ formatString.push_back('0');
+ }
+ // Right justify (or left justify if negative)
+ int32_t justify = dataProvider->ConsumeIntegralInRange<int32_t>(-kMaxFormatFlagValue,
+ kMaxFormatFlagValue);
+ formatString += std::to_string(justify);
+ }
+
+ // The # specifier only works with o, x, X, a, A, e, E, f, F, g, and G
+ if (canApplyFlag(formatType, '#') && dataProvider->ConsumeBool()) {
+ formatString.push_back('#');
+ }
+
+ // Precision specifier
+ if (canApplyFlag(formatType, '.') && dataProvider->ConsumeBool()) {
+ formatString.push_back('.');
+ formatString +=
+ std::to_string(dataProvider->ConsumeIntegralInRange<int>(0, kMaxFormatFlagValue));
+ }
+
+ formatString.push_back(kFormatChars.at(static_cast<uint8_t>(formatType)));
+
+ switch (formatType) {
+ case SIGNED_DECIMAL: {
+ int val = dataProvider->ConsumeIntegral<int>();
+ if (shouldAppend) {
+ str1->appendFormat(formatString.c_str(), val);
+ } else {
+ str1->format(formatString.c_str(), dataProvider->ConsumeIntegral<int>());
+ }
+ break;
+ }
+
+ case UNSIGNED_DECIMAL:
+ case UNSIGNED_OCTAL:
+ case UNSIGNED_HEX_LOWER:
+ case UNSIGNED_HEX_UPPER: {
+ // Unsigned integers for u, o, x, and X
+ uint val = dataProvider->ConsumeIntegral<uint>();
+ if (shouldAppend) {
+ str1->appendFormat(formatString.c_str(), val);
+ } else {
+ str1->format(formatString.c_str(), val);
+ }
+ break;
+ }
+
+ case FLOAT_LOWER:
+ case FLOAT_UPPER:
+ case EXPONENT_LOWER:
+ case EXPONENT_UPPER:
+ case SHORT_EXP_LOWER:
+ case SHORT_EXP_UPPER:
+ case HEX_FLOAT_LOWER:
+ case HEX_FLOAT_UPPER: {
+ // Floating points for f, F, e, E, g, G, a, and A
+ float val = dataProvider->ConsumeFloatingPoint<float>();
+ if (shouldAppend) {
+ str1->appendFormat(formatString.c_str(), val);
+ } else {
+ str1->format(formatString.c_str(), val);
+ }
+ break;
+ }
+
+ case CHAR: {
+ char val = dataProvider->ConsumeIntegral<char>();
+ if (shouldAppend) {
+ str1->appendFormat(formatString.c_str(), val);
+ } else {
+ str1->format(formatString.c_str(), val);
+ }
+ break;
+ }
+
+ case STRING: {
+ std::string val = dataProvider->ConsumeRandomLengthString(MAX_STRING_BYTES);
+ if (shouldAppend) {
+ str1->appendFormat(formatString.c_str(), val.c_str());
+ } else {
+ str1->format(formatString.c_str(), val.c_str());
+ }
+ break;
+ }
+ case POINTER: {
+ uintptr_t val = dataProvider->ConsumeIntegral<uintptr_t>();
+ if (shouldAppend) {
+ str1->appendFormat(formatString.c_str(), val);
+ } else {
+ str1->format(formatString.c_str(), val);
+ }
+ break;
+ }
+ }
+}
+
+void callFunc(uint8_t index, FuzzedDataProvider* dataProvider, android::String8* str1,
+ android::String8* str2) {
+ operations[index](dataProvider, str1, str2);
+}
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+ FuzzedDataProvider dataProvider(data, size);
+ // Generate vector lengths
+ const size_t kVecOneLen = dataProvider.ConsumeIntegralInRange<size_t>(1, MAX_STRING_BYTES);
+ const size_t kVecTwoLen = dataProvider.ConsumeIntegralInRange<size_t>(1, MAX_STRING_BYTES);
+ // Populate vectors
+ std::vector<char> vec = dataProvider.ConsumeBytesWithTerminator<char>(kVecOneLen);
+ std::vector<char> vec_two = dataProvider.ConsumeBytesWithTerminator<char>(kVecTwoLen);
+ // Create UTF-8 pointers
+ android::String8 str_one_utf8 = android::String8(vec.data());
+ android::String8 str_two_utf8 = android::String8(vec_two.data());
+ // Run operations against strings
+ int opsRun = 0;
+ while (dataProvider.remaining_bytes() > 0 && opsRun++ < MAX_OPERATIONS) {
+ uint8_t op = dataProvider.ConsumeIntegralInRange<uint8_t>(0, operations.size() - 1);
+ operations[op](&dataProvider, &str_one_utf8, &str_two_utf8);
+ }
+ // Just to be extra sure these can be freed, we're going to explicitly clear
+ // them
+ str_one_utf8.clear();
+ str_two_utf8.clear();
+ return 0;
+}
diff --git a/libutils/binder/String8_test.cpp b/libutils/binder/String8_test.cpp
new file mode 100644
index 0000000..6f7882a
--- /dev/null
+++ b/libutils/binder/String8_test.cpp
@@ -0,0 +1,134 @@
+/*
+ * Copyright (C) 2010 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.
+ */
+
+#define LOG_TAG "String8_test"
+
+#include <log/log.h>
+#include <utils/String8.h>
+#include <utils/String16.h>
+
+#include <gtest/gtest.h>
+
+using namespace android;
+
+class String8Test : public testing::Test {
+protected:
+ virtual void SetUp() {
+ }
+
+ virtual void TearDown() {
+ }
+};
+
+TEST_F(String8Test, Cstr) {
+ String8 tmp("Hello, world!");
+
+ EXPECT_STREQ(tmp.c_str(), "Hello, world!");
+}
+
+TEST_F(String8Test, OperatorPlus) {
+ String8 src1("Hello, ");
+
+ // Test adding String8 + const char*
+ const char* ccsrc2 = "world!";
+ String8 dst1 = src1 + ccsrc2;
+ EXPECT_STREQ(dst1.c_str(), "Hello, world!");
+ EXPECT_STREQ(src1.c_str(), "Hello, ");
+ EXPECT_STREQ(ccsrc2, "world!");
+
+ // Test adding String8 + String8
+ String8 ssrc2("world!");
+ String8 dst2 = src1 + ssrc2;
+ EXPECT_STREQ(dst2.c_str(), "Hello, world!");
+ EXPECT_STREQ(src1.c_str(), "Hello, ");
+ EXPECT_STREQ(ssrc2.c_str(), "world!");
+}
+
+TEST_F(String8Test, OperatorPlusEquals) {
+ String8 src1("My voice");
+
+ // Testing String8 += String8
+ String8 src2(" is my passport.");
+ src1 += src2;
+ EXPECT_STREQ(src1.c_str(), "My voice is my passport.");
+ EXPECT_STREQ(src2.c_str(), " is my passport.");
+
+ // Adding const char* to the previous string.
+ const char* src3 = " Verify me.";
+ src1 += src3;
+ EXPECT_STREQ(src1.c_str(), "My voice is my passport. Verify me.");
+ EXPECT_STREQ(src2.c_str(), " is my passport.");
+ EXPECT_STREQ(src3, " Verify me.");
+}
+
+TEST_F(String8Test, SetToSizeMaxReturnsNoMemory) {
+ const char *in = "some string";
+ EXPECT_EQ(NO_MEMORY, String8("").setTo(in, SIZE_MAX));
+}
+
+// http://b/29250543
+TEST_F(String8Test, CorrectInvalidSurrogate) {
+ // d841d8 is an invalid start for a surrogate pair. Make sure this is handled by ignoring the
+ // first character in the pair and handling the rest correctly.
+ String16 string16(u"\xd841\xd841\xdc41\x0000");
+ String8 string8(string16);
+
+ EXPECT_EQ(4U, string8.length());
+}
+
+TEST_F(String8Test, CheckUtf32Conversion) {
+ // Since bound checks were added, check the conversion can be done without fatal errors.
+ // The utf8 lengths of these are chars are 1 + 2 + 3 + 4 = 10.
+ const char32_t string32[] = U"\x0000007f\x000007ff\x0000911\x0010fffe";
+ String8 string8(string32);
+ EXPECT_EQ(10U, string8.length());
+}
+
+TEST_F(String8Test, ValidUtf16Conversion) {
+ char16_t tmp[] = u"abcdef";
+ String8 valid = String8(String16(tmp));
+ EXPECT_STREQ(valid.c_str(), "abcdef");
+}
+
+TEST_F(String8Test, append) {
+ String8 s;
+ EXPECT_EQ(OK, s.append("foo"));
+ EXPECT_STREQ("foo", s.c_str());
+ EXPECT_EQ(OK, s.append("bar"));
+ EXPECT_STREQ("foobar", s.c_str());
+ EXPECT_EQ(OK, s.append("baz", 0));
+ EXPECT_STREQ("foobar", s.c_str());
+ EXPECT_EQ(NO_MEMORY, s.append("baz", SIZE_MAX));
+ EXPECT_STREQ("foobar", s.c_str());
+}
+
+TEST_F(String8Test, removeAll) {
+ String8 s("Hello, world!");
+
+ // NULL input should cause an assertion failure and error message in logcat
+ EXPECT_DEATH(s.removeAll(NULL), "");
+
+ // expect to return true and string content should remain unchanged
+ EXPECT_TRUE(s.removeAll(""));
+ EXPECT_STREQ("Hello, world!", s.c_str());
+
+ // expect to return false
+ EXPECT_FALSE(s.removeAll("x"));
+ EXPECT_STREQ("Hello, world!", s.c_str());
+
+ EXPECT_TRUE(s.removeAll("o"));
+ EXPECT_STREQ("Hell, wrld!", s.c_str());
+}
diff --git a/libutils/binder/StrongPointer.cpp b/libutils/binder/StrongPointer.cpp
new file mode 100644
index 0000000..ba52502
--- /dev/null
+++ b/libutils/binder/StrongPointer.cpp
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+#define LOG_TAG "sp"
+
+#include <log/log.h>
+
+namespace android {
+
+void sp_report_race() { LOG_ALWAYS_FATAL("sp<> assignment detected data race"); }
+}
diff --git a/libutils/binder/StrongPointer_test.cpp b/libutils/binder/StrongPointer_test.cpp
new file mode 100644
index 0000000..f27c1f1
--- /dev/null
+++ b/libutils/binder/StrongPointer_test.cpp
@@ -0,0 +1,108 @@
+/*
+ * Copyright (C) 2015 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 <gtest/gtest.h>
+
+#include <utils/StrongPointer.h>
+#include <utils/RefBase.h>
+
+using namespace android;
+
+class SPFoo : virtual public RefBase {
+ public:
+ explicit SPFoo(bool* deleted_check) : mDeleted(deleted_check) {
+ *mDeleted = false;
+ }
+
+ ~SPFoo() {
+ *mDeleted = true;
+ }
+
+ private:
+ bool* mDeleted;
+};
+
+class SPLightFoo : virtual public VirtualLightRefBase {
+ public:
+ explicit SPLightFoo(bool* deleted_check) : mDeleted(deleted_check) { *mDeleted = false; }
+
+ ~SPLightFoo() { *mDeleted = true; }
+
+ private:
+ bool* mDeleted;
+};
+
+template <typename T>
+class StrongPointer : public ::testing::Test {};
+
+using RefBaseTypes = ::testing::Types<SPFoo, SPLightFoo>;
+TYPED_TEST_CASE(StrongPointer, RefBaseTypes);
+
+TYPED_TEST(StrongPointer, move) {
+ bool isDeleted;
+ sp<TypeParam> sp1 = sp<TypeParam>::make(&isDeleted);
+ TypeParam* foo = sp1.get();
+ ASSERT_EQ(1, foo->getStrongCount());
+ {
+ sp<TypeParam> sp2 = std::move(sp1);
+ ASSERT_EQ(1, foo->getStrongCount()) << "std::move failed, incremented refcnt";
+ ASSERT_EQ(nullptr, sp1.get()) << "std::move failed, sp1 is still valid";
+ // The strong count isn't increasing, let's double check the old object
+ // is properly reset and doesn't early delete
+ sp1 = std::move(sp2);
+ }
+ ASSERT_FALSE(isDeleted) << "deleted too early! still has a reference!";
+ {
+ // Now let's double check it deletes on time
+ sp<TypeParam> sp2 = std::move(sp1);
+ }
+ ASSERT_TRUE(isDeleted) << "foo was leaked!";
+}
+
+TYPED_TEST(StrongPointer, NullptrComparison) {
+ sp<TypeParam> foo;
+ ASSERT_EQ(foo, nullptr);
+ ASSERT_EQ(nullptr, foo);
+}
+
+TYPED_TEST(StrongPointer, PointerComparison) {
+ bool isDeleted;
+ sp<TypeParam> foo = sp<TypeParam>::make(&isDeleted);
+ ASSERT_EQ(foo.get(), foo);
+ ASSERT_EQ(foo, foo.get());
+ ASSERT_NE(nullptr, foo);
+ ASSERT_NE(foo, nullptr);
+}
+
+TYPED_TEST(StrongPointer, Deleted) {
+ bool isDeleted;
+ sp<TypeParam> foo = sp<TypeParam>::make(&isDeleted);
+
+ auto foo2 = sp<TypeParam>::fromExisting(foo.get());
+
+ EXPECT_FALSE(isDeleted);
+ foo = nullptr;
+ EXPECT_FALSE(isDeleted);
+ foo2 = nullptr;
+ EXPECT_TRUE(isDeleted);
+}
+
+TYPED_TEST(StrongPointer, AssertStrongRefExists) {
+ bool isDeleted;
+ TypeParam* foo = new TypeParam(&isDeleted);
+ EXPECT_DEATH(sp<TypeParam>::fromExisting(foo), "");
+ delete foo;
+}
diff --git a/libutils/binder/Unicode.cpp b/libutils/binder/Unicode.cpp
new file mode 100644
index 0000000..364a177
--- /dev/null
+++ b/libutils/binder/Unicode.cpp
@@ -0,0 +1,541 @@
+/*
+ * Copyright (C) 2005 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.
+ */
+
+#define LOG_TAG "unicode"
+
+#include <android-base/macros.h>
+#include <limits.h>
+#include <utils/Unicode.h>
+
+#include <log/log.h>
+
+extern "C" {
+
+static const char32_t kByteMask = 0x000000BF;
+static const char32_t kByteMark = 0x00000080;
+
+// Surrogates aren't valid for UTF-32 characters, so define some
+// constants that will let us screen them out.
+static const char32_t kUnicodeSurrogateHighStart = 0x0000D800;
+// Unused, here for completeness:
+// static const char32_t kUnicodeSurrogateHighEnd = 0x0000DBFF;
+// static const char32_t kUnicodeSurrogateLowStart = 0x0000DC00;
+static const char32_t kUnicodeSurrogateLowEnd = 0x0000DFFF;
+static const char32_t kUnicodeSurrogateStart = kUnicodeSurrogateHighStart;
+static const char32_t kUnicodeSurrogateEnd = kUnicodeSurrogateLowEnd;
+static const char32_t kUnicodeMaxCodepoint = 0x0010FFFF;
+
+// Mask used to set appropriate bits in first byte of UTF-8 sequence,
+// indexed by number of bytes in the sequence.
+// 0xxxxxxx
+// -> (00-7f) 7bit. Bit mask for the first byte is 0x00000000
+// 110yyyyx 10xxxxxx
+// -> (c0-df)(80-bf) 11bit. Bit mask is 0x000000C0
+// 1110yyyy 10yxxxxx 10xxxxxx
+// -> (e0-ef)(80-bf)(80-bf) 16bit. Bit mask is 0x000000E0
+// 11110yyy 10yyxxxx 10xxxxxx 10xxxxxx
+// -> (f0-f7)(80-bf)(80-bf)(80-bf) 21bit. Bit mask is 0x000000F0
+static const char32_t kFirstByteMark[] = {
+ 0x00000000, 0x00000000, 0x000000C0, 0x000000E0, 0x000000F0
+};
+
+// --------------------------------------------------------------------------
+// UTF-32
+// --------------------------------------------------------------------------
+
+/**
+ * Return number of UTF-8 bytes required for the character. If the character
+ * is invalid, return size of 0.
+ */
+static inline size_t utf32_codepoint_utf8_length(char32_t srcChar)
+{
+ // Figure out how many bytes the result will require.
+ if (srcChar < 0x00000080) {
+ return 1;
+ } else if (srcChar < 0x00000800) {
+ return 2;
+ } else if (srcChar < 0x00010000) {
+ if ((srcChar < kUnicodeSurrogateStart) || (srcChar > kUnicodeSurrogateEnd)) {
+ return 3;
+ } else {
+ // Surrogates are invalid UTF-32 characters.
+ return 0;
+ }
+ }
+ // Max code point for Unicode is 0x0010FFFF.
+ else if (srcChar <= kUnicodeMaxCodepoint) {
+ return 4;
+ } else {
+ // Invalid UTF-32 character.
+ return 0;
+ }
+}
+
+// Write out the source character to <dstP>.
+
+static inline void utf32_codepoint_to_utf8(uint8_t* dstP, char32_t srcChar, size_t bytes)
+{
+ dstP += bytes;
+ switch (bytes)
+ { /* note: everything falls through. */
+ case 4: *--dstP = (uint8_t)((srcChar | kByteMark) & kByteMask); srcChar >>= 6;
+ FALLTHROUGH_INTENDED;
+ case 3: *--dstP = (uint8_t)((srcChar | kByteMark) & kByteMask); srcChar >>= 6;
+ FALLTHROUGH_INTENDED;
+ case 2: *--dstP = (uint8_t)((srcChar | kByteMark) & kByteMask); srcChar >>= 6;
+ FALLTHROUGH_INTENDED;
+ case 1: *--dstP = (uint8_t)(srcChar | kFirstByteMark[bytes]);
+ }
+}
+
+static inline int32_t utf32_at_internal(const char* cur, size_t *num_read)
+{
+ const char first_char = *cur;
+ if ((first_char & 0x80) == 0) { // ASCII
+ *num_read = 1;
+ return *cur;
+ }
+ cur++;
+ char32_t mask, to_ignore_mask;
+ size_t num_to_read = 0;
+ char32_t utf32 = first_char;
+ for (num_to_read = 1, mask = 0x40, to_ignore_mask = 0xFFFFFF80;
+ (first_char & mask);
+ num_to_read++, to_ignore_mask |= mask, mask >>= 1) {
+ // 0x3F == 00111111
+ utf32 = (utf32 << 6) + (*cur++ & 0x3F);
+ }
+ to_ignore_mask |= mask;
+ utf32 &= ~(to_ignore_mask << (6 * (num_to_read - 1)));
+
+ *num_read = num_to_read;
+ return static_cast<int32_t>(utf32);
+}
+
+int32_t utf32_from_utf8_at(const char *src, size_t src_len, size_t index, size_t *next_index)
+{
+ if (index >= src_len) {
+ return -1;
+ }
+ size_t unused_index;
+ if (next_index == nullptr) {
+ next_index = &unused_index;
+ }
+ size_t num_read;
+ int32_t ret = utf32_at_internal(src + index, &num_read);
+ if (ret >= 0) {
+ *next_index = index + num_read;
+ }
+
+ return ret;
+}
+
+ssize_t utf32_to_utf8_length(const char32_t *src, size_t src_len)
+{
+ if (src == nullptr || src_len == 0) {
+ return -1;
+ }
+
+ size_t ret = 0;
+ const char32_t *end = src + src_len;
+ while (src < end) {
+ size_t char_len = utf32_codepoint_utf8_length(*src++);
+ if (SSIZE_MAX - char_len < ret) {
+ // If this happens, we would overflow the ssize_t type when
+ // returning from this function, so we cannot express how
+ // long this string is in an ssize_t.
+ android_errorWriteLog(0x534e4554, "37723026");
+ return -1;
+ }
+ ret += char_len;
+ }
+ return ret;
+}
+
+void utf32_to_utf8(const char32_t* src, size_t src_len, char* dst, size_t dst_len)
+{
+ if (src == nullptr || src_len == 0 || dst == nullptr) {
+ return;
+ }
+
+ const char32_t *cur_utf32 = src;
+ const char32_t *end_utf32 = src + src_len;
+ char *cur = dst;
+ while (cur_utf32 < end_utf32) {
+ size_t len = utf32_codepoint_utf8_length(*cur_utf32);
+ LOG_ALWAYS_FATAL_IF(dst_len < len, "%zu < %zu", dst_len, len);
+ utf32_codepoint_to_utf8((uint8_t *)cur, *cur_utf32++, len);
+ cur += len;
+ dst_len -= len;
+ }
+ LOG_ALWAYS_FATAL_IF(dst_len < 1, "dst_len < 1: %zu < 1", dst_len);
+ *cur = '\0';
+}
+
+// --------------------------------------------------------------------------
+// UTF-16
+// --------------------------------------------------------------------------
+
+int strcmp16(const char16_t *s1, const char16_t *s2)
+{
+ char16_t ch;
+ int d = 0;
+
+ while ( 1 ) {
+ d = (int)(ch = *s1++) - (int)*s2++;
+ if ( d || !ch )
+ break;
+ }
+
+ return d;
+}
+
+int strncmp16(const char16_t *s1, const char16_t *s2, size_t n)
+{
+ char16_t ch;
+ int d = 0;
+
+ if (n == 0) {
+ return 0;
+ }
+
+ do {
+ d = (int)(ch = *s1++) - (int)*s2++;
+ if ( d || !ch ) {
+ break;
+ }
+ } while (--n);
+
+ return d;
+}
+
+size_t strlen16(const char16_t *s)
+{
+ const char16_t *ss = s;
+ while ( *ss )
+ ss++;
+ return ss-s;
+}
+
+size_t strnlen16(const char16_t *s, size_t maxlen)
+{
+ const char16_t *ss = s;
+
+ /* Important: the maxlen test must precede the reference through ss;
+ since the byte beyond the maximum may segfault */
+ while ((maxlen > 0) && *ss) {
+ ss++;
+ maxlen--;
+ }
+ return ss-s;
+}
+
+char16_t* strstr16(const char16_t* src, const char16_t* target)
+{
+ const char16_t needle = *target;
+ if (needle == '\0') return (char16_t*)src;
+
+ const size_t target_len = strlen16(++target);
+ do {
+ do {
+ if (*src == '\0') {
+ return nullptr;
+ }
+ } while (*src++ != needle);
+ } while (strncmp16(src, target, target_len) != 0);
+ src--;
+
+ return (char16_t*)src;
+}
+
+int strzcmp16(const char16_t *s1, size_t n1, const char16_t *s2, size_t n2)
+{
+ const char16_t* e1 = s1+n1;
+ const char16_t* e2 = s2+n2;
+
+ while (s1 < e1 && s2 < e2) {
+ const int d = (int)*s1++ - (int)*s2++;
+ if (d) {
+ return d;
+ }
+ }
+
+ return n1 < n2
+ ? (0 - (int)*s2)
+ : (n1 > n2
+ ? ((int)*s1 - 0)
+ : 0);
+}
+
+// is_any_surrogate() returns true if w is either a high or low surrogate
+static constexpr bool is_any_surrogate(char16_t w) {
+ return (w & 0xf800) == 0xd800;
+}
+
+// is_surrogate_pair() returns true if w1 and w2 form a valid surrogate pair
+static constexpr bool is_surrogate_pair(char16_t w1, char16_t w2) {
+ return ((w1 & 0xfc00) == 0xd800) && ((w2 & 0xfc00) == 0xdc00);
+}
+
+// TODO: currently utf16_to_utf8_length() returns -1 if src_len == 0,
+// which is inconsistent with utf8_to_utf16_length(), here we keep the
+// current behavior as intended not to break compatibility
+ssize_t utf16_to_utf8_length(const char16_t *src, size_t src_len)
+{
+ if (src == nullptr || src_len == 0)
+ return -1;
+
+ const char16_t* const end = src + src_len;
+ const char16_t* in = src;
+ size_t utf8_len = 0;
+
+ while (in < end) {
+ char16_t w = *in++;
+ if (LIKELY(w < 0x0080)) {
+ utf8_len += 1;
+ continue;
+ }
+ if (LIKELY(w < 0x0800)) {
+ utf8_len += 2;
+ continue;
+ }
+ if (LIKELY(!is_any_surrogate(w))) {
+ utf8_len += 3;
+ continue;
+ }
+ if (in < end && is_surrogate_pair(w, *in)) {
+ utf8_len += 4;
+ in++;
+ continue;
+ }
+ /* skip if at the end of the string or invalid surrogate pair */
+ }
+ return (in == end && utf8_len < SSIZE_MAX) ? utf8_len : -1;
+}
+
+void utf16_to_utf8(const char16_t* src, size_t src_len, char* dst, size_t dst_len)
+{
+ if (src == nullptr || src_len == 0 || dst == nullptr) {
+ return;
+ }
+
+ const char16_t* in = src;
+ const char16_t* const in_end = src + src_len;
+ char* out = dst;
+ const char* const out_end = dst + dst_len;
+ char16_t w2;
+
+ auto err_out = [&out, &out_end, &dst_len]() {
+ LOG_ALWAYS_FATAL_IF(out >= out_end,
+ "target utf8 string size %zu too short", dst_len);
+ };
+
+ while (in < in_end) {
+ char16_t w = *in++;
+ if (LIKELY(w < 0x0080)) {
+ if (out + 1 > out_end)
+ return err_out();
+ *out++ = (char)(w & 0xff);
+ continue;
+ }
+ if (LIKELY(w < 0x0800)) {
+ if (out + 2 > out_end)
+ return err_out();
+ *out++ = (char)(0xc0 | ((w >> 6) & 0x1f));
+ *out++ = (char)(0x80 | ((w >> 0) & 0x3f));
+ continue;
+ }
+ if (LIKELY(!is_any_surrogate(w))) {
+ if (out + 3 > out_end)
+ return err_out();
+ *out++ = (char)(0xe0 | ((w >> 12) & 0xf));
+ *out++ = (char)(0x80 | ((w >> 6) & 0x3f));
+ *out++ = (char)(0x80 | ((w >> 0) & 0x3f));
+ continue;
+ }
+ /* surrogate pair */
+ if (in < in_end && (w2 = *in, is_surrogate_pair(w, w2))) {
+ if (out + 4 > out_end)
+ return err_out();
+ char32_t dw = (char32_t)(0x10000 + ((w - 0xd800) << 10) + (w2 - 0xdc00));
+ *out++ = (char)(0xf0 | ((dw >> 18) & 0x07));
+ *out++ = (char)(0x80 | ((dw >> 12) & 0x3f));
+ *out++ = (char)(0x80 | ((dw >> 6) & 0x3f));
+ *out++ = (char)(0x80 | ((dw >> 0) & 0x3f));
+ in++;
+ }
+ /* We reach here in two cases:
+ * 1) (in == in_end), which means end of the input string
+ * 2) (w2 & 0xfc00) != 0xdc00, which means invalid surrogate pair
+ * In either case, we intentionally do nothing and skip
+ */
+ }
+ *out = '\0';
+ return;
+}
+
+// --------------------------------------------------------------------------
+// UTF-8
+// --------------------------------------------------------------------------
+
+static char32_t utf8_4b_to_utf32(uint8_t c1, uint8_t c2, uint8_t c3, uint8_t c4) {
+ return ((c1 & 0x07) << 18) | ((c2 & 0x3f) << 12) | ((c3 & 0x3f) << 6) | (c4 & 0x3f);
+}
+
+// TODO: current behavior of converting UTF8 to UTF-16 has a few issues below
+//
+// 1. invalid trailing bytes (i.e. not b'10xxxxxx) are treated as valid trailing
+// bytes and follows normal conversion rules
+// 2. invalid leading byte (b'10xxxxxx) is treated as a valid single UTF-8 byte
+// 3. invalid leading byte (b'11111xxx) is treated as a valid leading byte
+// (same as b'11110xxx) for a 4-byte UTF-8 sequence
+// 4. an invalid 4-byte UTF-8 sequence that translates to a codepoint < U+10000
+// will be converted as a valid UTF-16 character
+//
+// We keep the current behavior as is but with warnings logged, so as not to
+// break compatibility. However, this needs to be addressed later.
+
+ssize_t utf8_to_utf16_length(const uint8_t* u8str, size_t u8len, bool overreadIsFatal)
+{
+ if (u8str == nullptr)
+ return -1;
+
+ const uint8_t* const in_end = u8str + u8len;
+ const uint8_t* in = u8str;
+ size_t utf16_len = 0;
+
+ while (in < in_end) {
+ uint8_t c = *in;
+ utf16_len++;
+ if (LIKELY((c & 0x80) == 0)) {
+ in++;
+ continue;
+ }
+ if (UNLIKELY(c < 0xc0)) {
+ ALOGW("Invalid UTF-8 leading byte: 0x%02x", c);
+ in++;
+ continue;
+ }
+ if (LIKELY(c < 0xe0)) {
+ in += 2;
+ continue;
+ }
+ if (LIKELY(c < 0xf0)) {
+ in += 3;
+ continue;
+ } else {
+ uint8_t c2, c3, c4;
+ if (UNLIKELY(c >= 0xf8)) {
+ ALOGW("Invalid UTF-8 leading byte: 0x%02x", c);
+ }
+ c2 = in[1]; c3 = in[2]; c4 = in[3];
+ if (utf8_4b_to_utf32(c, c2, c3, c4) >= 0x10000) {
+ utf16_len++;
+ }
+ in += 4;
+ continue;
+ }
+ }
+ if (in == in_end) {
+ return utf16_len < SSIZE_MAX ? utf16_len : -1;
+ }
+ if (overreadIsFatal)
+ LOG_ALWAYS_FATAL("Attempt to overread computing length of utf8 string");
+ return -1;
+}
+
+char16_t* utf8_to_utf16(const uint8_t* u8str, size_t u8len, char16_t* u16str, size_t u16len) {
+ // A value > SSIZE_MAX is probably a negative value returned as an error and casted.
+ LOG_ALWAYS_FATAL_IF(u16len == 0 || u16len > SSIZE_MAX, "u16len is %zu", u16len);
+ char16_t* end = utf8_to_utf16_no_null_terminator(u8str, u8len, u16str, u16len - 1);
+ *end = 0;
+ return end;
+}
+
+char16_t* utf8_to_utf16_no_null_terminator(
+ const uint8_t* src, size_t srcLen, char16_t* dst, size_t dstLen) {
+ if (src == nullptr || srcLen == 0 || dstLen == 0) {
+ return dst;
+ }
+ // A value > SSIZE_MAX is probably a negative value returned as an error and casted.
+ LOG_ALWAYS_FATAL_IF(dstLen > SSIZE_MAX, "dstLen is %zu", dstLen);
+
+ const uint8_t* const in_end = src + srcLen;
+ const uint8_t* in = src;
+ const char16_t* const out_end = dst + dstLen;
+ char16_t* out = dst;
+ uint8_t c, c2, c3, c4;
+ char32_t w;
+
+ auto err_in = [&c, &out]() {
+ ALOGW("Unended UTF-8 byte: 0x%02x", c);
+ return out;
+ };
+
+ while (in < in_end && out < out_end) {
+ c = *in++;
+ if (LIKELY((c & 0x80) == 0)) {
+ *out++ = (char16_t)(c);
+ continue;
+ }
+ if (UNLIKELY(c < 0xc0)) {
+ ALOGW("Invalid UTF-8 leading byte: 0x%02x", c);
+ *out++ = (char16_t)(c);
+ continue;
+ }
+ if (LIKELY(c < 0xe0)) {
+ if (UNLIKELY(in + 1 > in_end)) {
+ return err_in();
+ }
+ c2 = *in++;
+ *out++ = (char16_t)(((c & 0x1f) << 6) | (c2 & 0x3f));
+ continue;
+ }
+ if (LIKELY(c < 0xf0)) {
+ if (UNLIKELY(in + 2 > in_end)) {
+ return err_in();
+ }
+ c2 = *in++; c3 = *in++;
+ *out++ = (char16_t)(((c & 0x0f) << 12) |
+ ((c2 & 0x3f) << 6) | (c3 & 0x3f));
+ continue;
+ } else {
+ if (UNLIKELY(in + 3 > in_end)) {
+ return err_in();
+ }
+ if (UNLIKELY(c >= 0xf8)) {
+ ALOGW("Invalid UTF-8 leading byte: 0x%02x", c);
+ }
+ // Multiple UTF16 characters with surrogates
+ c2 = *in++; c3 = *in++; c4 = *in++;
+ w = utf8_4b_to_utf32(c, c2, c3, c4);
+ if (UNLIKELY(w < 0x10000)) {
+ *out++ = (char16_t)(w);
+ } else {
+ if (UNLIKELY(out + 2 > out_end)) {
+ // Ooops.... not enough room for this surrogate pair.
+ return out;
+ }
+ *out++ = (char16_t)(((w - 0x10000) >> 10) + 0xd800);
+ *out++ = (char16_t)(((w - 0x10000) & 0x3ff) + 0xdc00);
+ }
+ continue;
+ }
+ }
+ return out;
+}
+
+}
diff --git a/libutils/binder/Unicode_test.cpp b/libutils/binder/Unicode_test.cpp
new file mode 100644
index 0000000..7969525
--- /dev/null
+++ b/libutils/binder/Unicode_test.cpp
@@ -0,0 +1,311 @@
+/*
+ * Copyright (C) 2010 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.
+ */
+
+#define LOG_TAG "Unicode_test"
+
+#include <sys/mman.h>
+#include <unistd.h>
+
+#include <log/log.h>
+#include <utils/Unicode.h>
+
+#include <gtest/gtest.h>
+
+namespace android {
+
+class UnicodeTest : public testing::Test {
+protected:
+ virtual void SetUp() {
+ }
+
+ virtual void TearDown() {
+ }
+
+ char16_t const * const kSearchString = u"I am a leaf on the wind.";
+
+ constexpr static size_t BUFSIZE = 64; // large enough for all tests
+
+ void TestUTF8toUTF16(std::initializer_list<uint8_t> input,
+ std::initializer_list<char16_t> expect,
+ const char* err_msg_length = "",
+ ssize_t expected_length = 0) {
+ uint8_t empty_str[] = {};
+ char16_t output[BUFSIZE];
+
+ const size_t inlen = input.size(), outlen = expect.size();
+ ASSERT_LT(outlen, BUFSIZE);
+
+ const uint8_t *input_data = inlen ? std::data(input) : empty_str;
+ ssize_t measured = utf8_to_utf16_length(input_data, inlen);
+ EXPECT_EQ(expected_length ? : (ssize_t)outlen, measured) << err_msg_length;
+
+ utf8_to_utf16(input_data, inlen, output, outlen + 1);
+ for (size_t i = 0; i < outlen; i++) {
+ EXPECT_EQ(std::data(expect)[i], output[i]);
+ }
+ EXPECT_EQ(0, output[outlen]) << "should be null terminated";
+ }
+
+ void TestUTF16toUTF8(std::initializer_list<char16_t> input,
+ std::initializer_list<char> expect,
+ const char* err_msg_length = "",
+ ssize_t expected_length = 0) {
+ char16_t empty_str[] = {};
+ char output[BUFSIZE];
+
+ const size_t inlen = input.size(), outlen = expect.size();
+ ASSERT_LT(outlen, BUFSIZE);
+
+ const char16_t *input_data = inlen ? std::data(input) : empty_str;
+ ssize_t measured = utf16_to_utf8_length(input_data, inlen);
+ EXPECT_EQ(expected_length ? : (ssize_t)outlen, measured) << err_msg_length;
+
+ utf16_to_utf8(input_data, inlen, output, outlen + 1);
+ for (size_t i = 0; i < outlen; i++) {
+ EXPECT_EQ(std::data(expect)[i], output[i]);
+ }
+ EXPECT_EQ(0, output[outlen]) << "should be null terminated";
+ }
+};
+
+TEST_F(UnicodeTest, UTF8toUTF16ZeroLength) {
+ TestUTF8toUTF16({}, {},
+ "Zero length input should return zero length output.");
+}
+
+TEST_F(UnicodeTest, UTF8toUTF16ASCII) {
+ TestUTF8toUTF16(
+ { 0x30 }, // U+0030 or ASCII '0'
+ { 0x0030 },
+ "ASCII codepoints should have a length of 1 char16_t");
+}
+
+TEST_F(UnicodeTest, UTF8toUTF16Plane1) {
+ TestUTF8toUTF16(
+ { 0xE2, 0x8C, 0xA3 }, // U+2323 SMILE
+ { 0x2323 },
+ "Plane 1 codepoints should have a length of 1 char16_t");
+}
+
+TEST_F(UnicodeTest, UTF8toUTF16Surrogate) {
+ TestUTF8toUTF16(
+ { 0xF0, 0x90, 0x80, 0x80 }, // U+10000
+ { 0xD800, 0xDC00 },
+ "Surrogate pairs should have a length of 2 char16_t");
+}
+
+TEST_F(UnicodeTest, UTF8toUTF16TruncatedUTF8) {
+ TestUTF8toUTF16(
+ { 0xE2, 0x8C }, // Truncated U+2323 SMILE
+ { }, // Conversion should still work but produce nothing
+ "Truncated UTF-8 should return -1 to indicate invalid",
+ -1);
+}
+
+TEST_F(UnicodeTest, UTF8toUTF16Normal) {
+ TestUTF8toUTF16({
+ 0x30, // U+0030, 1 UTF-16 character
+ 0xC4, 0x80, // U+0100, 1 UTF-16 character
+ 0xE2, 0x8C, 0xA3, // U+2323, 1 UTF-16 character
+ 0xF0, 0x90, 0x80, 0x80, // U+10000, 2 UTF-16 character
+ }, {
+ 0x0030,
+ 0x0100,
+ 0x2323,
+ 0xD800, 0xDC00
+ });
+}
+
+TEST_F(UnicodeTest, UTF8toUTF16Invalid) {
+ // TODO: The current behavior of utf8_to_utf16 is to treat invalid
+ // leading byte (>= 0xf8) as a 4-byte UTF8 sequence, and to treat
+ // invalid trailing byte(s) (i.e. bytes not having MSB set) as if
+ // they are valid and do the normal conversion. However, a better
+ // handling would be to treat invalid sequences as errors, such
+ // cases need to be reported and invalid characters (e.g. U+FFFD)
+ // could be produced at the place of error. Until a fix is ready
+ // and compatibility is not an issue, we will keep testing the
+ // current behavior
+ TestUTF8toUTF16({
+ 0xf8, // invalid leading byte
+ 0xc4, 0x00, // U+0100 with invalid trailing byte
+ 0xe2, 0x0c, 0xa3, // U+2323 with invalid trailing bytes
+ 0xf0, 0x10, 0x00, 0x00, // U+10000 with invalid trailing bytes
+ }, {
+ 0x4022, // invalid leading byte (>=0xfc) is treated
+ // as valid for 4-byte UTF8 sequence
+ 0x000C,
+ 0x00A3, // invalid leadnig byte (b'10xxxxxx) is
+ // treated as valid single UTF-8 byte
+ 0xD800, // invalid trailing bytes are treated
+ 0xDC00, // as valid bytes and follow normal
+ });
+}
+
+TEST_F(UnicodeTest, UTF16toUTF8ZeroLength) {
+ // TODO: The current behavior of utf16_to_utf8_length() is that
+ // it returns -1 if the input is a zero length UTF16 string.
+ // This is inconsistent with utf8_to_utf16_length() where a zero
+ // length string returns 0. However, to fix the current behavior,
+ // we could have compatibility issue. Until then, we will keep
+ // testing the current behavior
+ TestUTF16toUTF8({}, {},
+ "Zero length UTF16 input should return length of -1.", -1);
+}
+
+TEST_F(UnicodeTest, UTF16toUTF8ASCII) {
+ TestUTF16toUTF8(
+ { 0x0030 }, // U+0030 or ASCII '0'
+ { '\x30' },
+ "ASCII codepoints in UTF16 should give a length of 1 in UTF8");
+}
+
+TEST_F(UnicodeTest, UTF16toUTF8Plane1) {
+ TestUTF16toUTF8(
+ { 0x2323 }, // U+2323 SMILE
+ { '\xE2', '\x8C', '\xA3' },
+ "Plane 1 codepoints should have a length of 3 char in UTF-8");
+}
+
+TEST_F(UnicodeTest, UTF16toUTF8Surrogate) {
+ TestUTF16toUTF8(
+ { 0xD800, 0xDC00 }, // U+10000
+ { '\xF0', '\x90', '\x80', '\x80' },
+ "Surrogate pairs should have a length of 4 chars");
+}
+
+TEST_F(UnicodeTest, UTF16toUTF8UnpairedSurrogate) {
+ TestUTF16toUTF8(
+ { 0xD800 }, // U+10000 with high surrogate pair only
+ { }, // Unpaired surrogate should be ignored
+ "A single unpaired high surrogate should have a length of 0 chars");
+
+ TestUTF16toUTF8(
+ { 0xDC00 }, // U+10000 with low surrogate pair only
+ { }, // Unpaired surrogate should be ignored
+ "A single unpaired low surrogate should have a length of 0 chars");
+
+ TestUTF16toUTF8(
+ // U+0030, U+0100, U+10000 with high surrogate pair only, U+2323
+ { 0x0030, 0x0100, 0xDC00, 0x2323 },
+ { '\x30', '\xC4', '\x80', '\xE2', '\x8C', '\xA3' },
+ "Unpaired high surrogate should be skipped in the middle");
+
+ TestUTF16toUTF8(
+ // U+0030, U+0100, U+10000 with high surrogate pair only, U+2323
+ { 0x0030, 0x0100, 0xDC00, 0x2323 },
+ { '\x30', '\xC4', '\x80', '\xE2', '\x8C', '\xA3' },
+ "Unpaired low surrogate should be skipped in the middle");
+}
+
+TEST_F(UnicodeTest, UTF16toUTF8CorrectInvalidSurrogate) {
+ // http://b/29250543
+ // d841d8 is an invalid start for a surrogate pair. Make sure this is handled by ignoring the
+ // first character in the pair and handling the rest correctly.
+ TestUTF16toUTF8(
+ { 0xD841, 0xD841, 0xDC41 }, // U+20441
+ { '\xF0', '\xA0', '\x91', '\x81' },
+ "Invalid start for a surrogate pair should be ignored");
+}
+
+TEST_F(UnicodeTest, UTF16toUTF8Normal) {
+ TestUTF16toUTF8({
+ 0x0024, // U+0024 ($) --> 0x24, 1 UTF-8 byte
+ 0x00A3, // U+00A3 (£) --> 0xC2 0xA3, 2 UTF-8 bytes
+ 0x0939, // U+0939 (ह) --> 0xE0 0xA4 0xB9, 3 UTF-8 bytes
+ 0x20AC, // U+20AC (€) --> 0xE2 0x82 0xAC, 3 UTF-8 bytes
+ 0xD55C, // U+D55C (한)--> 0xED 0x95 0x9C, 3 UTF-8 bytes
+ 0xD801, 0xDC37, // U+10437 (𐐷) --> 0xF0 0x90 0x90 0xB7, 4 UTF-8 bytes
+ }, {
+ '\x24',
+ '\xC2', '\xA3',
+ '\xE0', '\xA4', '\xB9',
+ '\xE2', '\x82', '\xAC',
+ '\xED', '\x95', '\x9C',
+ '\xF0', '\x90', '\x90', '\xB7',
+ });
+}
+
+TEST_F(UnicodeTest, strstr16EmptyTarget) {
+ EXPECT_EQ(strstr16(kSearchString, u""), kSearchString)
+ << "should return the original pointer";
+}
+
+TEST_F(UnicodeTest, strstr16EmptyTarget_bug) {
+ // In the original code when target is an empty string strlen16() would
+ // start reading the memory until a "terminating null" (that is, zero)
+ // character is found. This happens because "*target++" in the original
+ // code would increment the pointer beyond the actual string.
+ void* memptr;
+ const size_t alignment = sysconf(_SC_PAGESIZE);
+ const size_t size = 2 * alignment;
+ ASSERT_EQ(posix_memalign(&memptr, alignment, size), 0);
+ // Fill allocated memory.
+ memset(memptr, 'A', size);
+ // Create a pointer to an "empty" string on the first page.
+ char16_t* const emptyString = (char16_t* const)((char*)memptr + alignment - 4);
+ *emptyString = (char16_t)0;
+ // Protect the second page to show that strstr16() violates that.
+ ASSERT_EQ(mprotect((char*)memptr + alignment, alignment, PROT_NONE), 0);
+ // Test strstr16(): when bug is present a segmentation fault is raised.
+ ASSERT_EQ(strstr16((char16_t*)memptr, emptyString), (char16_t*)memptr)
+ << "should not read beyond the first char16_t.";
+ // Reset protection of the second page
+ ASSERT_EQ(mprotect((char*)memptr + alignment, alignment, PROT_READ | PROT_WRITE), 0);
+ // Free allocated memory.
+ free(memptr);
+}
+
+TEST_F(UnicodeTest, strstr16SameString) {
+ const char16_t* result = strstr16(kSearchString, kSearchString);
+ EXPECT_EQ(kSearchString, result)
+ << "should return the original pointer";
+}
+
+TEST_F(UnicodeTest, strstr16TargetStartOfString) {
+ const char16_t* result = strstr16(kSearchString, u"I am");
+ EXPECT_EQ(kSearchString, result)
+ << "should return the original pointer";
+}
+
+
+TEST_F(UnicodeTest, strstr16TargetEndOfString) {
+ const char16_t* result = strstr16(kSearchString, u"wind.");
+ EXPECT_EQ(kSearchString+19, result);
+}
+
+TEST_F(UnicodeTest, strstr16TargetWithinString) {
+ const char16_t* result = strstr16(kSearchString, u"leaf");
+ EXPECT_EQ(kSearchString+7, result);
+}
+
+TEST_F(UnicodeTest, strstr16TargetNotPresent) {
+ const char16_t* result = strstr16(kSearchString, u"soar");
+ EXPECT_EQ(nullptr, result);
+}
+
+// http://b/29267949
+// Test that overreading in utf8_to_utf16_length is detected
+TEST_F(UnicodeTest, InvalidUtf8OverreadDetected) {
+ // An utf8 char starting with \xc4 is two bytes long.
+ // Add extra zeros so no extra memory is read in case the code doesn't
+ // work as expected.
+ static char utf8[] = "\xc4\x00\x00\x00";
+ ASSERT_DEATH(utf8_to_utf16_length((uint8_t *) utf8, strlen(utf8),
+ true /* overreadIsFatal */), "" /* regex for ASSERT_DEATH */);
+}
+
+}
diff --git a/libutils/binder/VectorImpl.cpp b/libutils/binder/VectorImpl.cpp
new file mode 100644
index 0000000..d951b8b
--- /dev/null
+++ b/libutils/binder/VectorImpl.cpp
@@ -0,0 +1,677 @@
+/*
+ * Copyright (C) 2005 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.
+ */
+
+#define LOG_TAG "Vector"
+
+#include <utils/VectorImpl.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <log/log.h>
+
+#include "SharedBuffer.h"
+
+/*****************************************************************************/
+
+
+namespace android {
+
+// ----------------------------------------------------------------------------
+
+const size_t kMinVectorCapacity = 4;
+
+static inline size_t max(size_t a, size_t b) {
+ return a>b ? a : b;
+}
+
+// ----------------------------------------------------------------------------
+
+VectorImpl::VectorImpl(size_t itemSize, uint32_t flags)
+ : mStorage(nullptr), mCount(0), mFlags(flags), mItemSize(itemSize)
+{
+}
+
+VectorImpl::VectorImpl(const VectorImpl& rhs)
+ : mStorage(rhs.mStorage), mCount(rhs.mCount),
+ mFlags(rhs.mFlags), mItemSize(rhs.mItemSize)
+{
+ if (mStorage) {
+ SharedBuffer::bufferFromData(mStorage)->acquire();
+ }
+}
+
+VectorImpl::~VectorImpl()
+{
+ ALOGW_IF(mCount,
+ "[%p] subclasses of VectorImpl must call finish_vector()"
+ " in their destructor. Leaking %d bytes.",
+ this, (int)(mCount*mItemSize));
+ // We can't call _do_destroy() here because the vtable is already gone.
+}
+
+VectorImpl& VectorImpl::operator = (const VectorImpl& rhs)
+{
+ LOG_ALWAYS_FATAL_IF(mItemSize != rhs.mItemSize,
+ "Vector<> have different types (this=%p, rhs=%p)", this, &rhs);
+ if (this != &rhs) {
+ release_storage();
+ if (rhs.mCount) {
+ mStorage = rhs.mStorage;
+ mCount = rhs.mCount;
+ SharedBuffer::bufferFromData(mStorage)->acquire();
+ } else {
+ mStorage = nullptr;
+ mCount = 0;
+ }
+ }
+ return *this;
+}
+
+void* VectorImpl::editArrayImpl()
+{
+ if (mStorage) {
+ const SharedBuffer* sb = SharedBuffer::bufferFromData(mStorage);
+ SharedBuffer* editable = sb->attemptEdit();
+ if (editable == nullptr) {
+ // If we're here, we're not the only owner of the buffer.
+ // We must make a copy of it.
+ editable = SharedBuffer::alloc(sb->size());
+ // Fail instead of returning a pointer to storage that's not
+ // editable. Otherwise we'd be editing the contents of a buffer
+ // for which we're not the only owner, which is undefined behaviour.
+ LOG_ALWAYS_FATAL_IF(editable == nullptr);
+ _do_copy(editable->data(), mStorage, mCount);
+ release_storage();
+ mStorage = editable->data();
+ }
+ }
+ return mStorage;
+}
+
+size_t VectorImpl::capacity() const
+{
+ if (mStorage) {
+ return SharedBuffer::bufferFromData(mStorage)->size() / mItemSize;
+ }
+ return 0;
+}
+
+ssize_t VectorImpl::insertVectorAt(const VectorImpl& vector, size_t index)
+{
+ return insertArrayAt(vector.arrayImpl(), index, vector.size());
+}
+
+ssize_t VectorImpl::appendVector(const VectorImpl& vector)
+{
+ return insertVectorAt(vector, size());
+}
+
+ssize_t VectorImpl::insertArrayAt(const void* array, size_t index, size_t length)
+{
+ if (index > size())
+ return BAD_INDEX;
+ void* where = _grow(index, length);
+ if (where) {
+ _do_copy(where, array, length);
+ }
+ return where ? index : (ssize_t)NO_MEMORY;
+}
+
+ssize_t VectorImpl::appendArray(const void* array, size_t length)
+{
+ return insertArrayAt(array, size(), length);
+}
+
+ssize_t VectorImpl::insertAt(size_t index, size_t numItems)
+{
+ return insertAt(nullptr, index, numItems);
+}
+
+ssize_t VectorImpl::insertAt(const void* item, size_t index, size_t numItems)
+{
+ if (index > size())
+ return BAD_INDEX;
+ void* where = _grow(index, numItems);
+ if (where) {
+ if (item) {
+ _do_splat(where, item, numItems);
+ } else {
+ _do_construct(where, numItems);
+ }
+ }
+ return where ? index : (ssize_t)NO_MEMORY;
+}
+
+static int sortProxy(const void* lhs, const void* rhs, void* func)
+{
+ return (*(VectorImpl::compar_t)func)(lhs, rhs);
+}
+
+status_t VectorImpl::sort(VectorImpl::compar_t cmp)
+{
+ return sort(sortProxy, (void*)cmp);
+}
+
+status_t VectorImpl::sort(VectorImpl::compar_r_t cmp, void* state)
+{
+ // the sort must be stable. we're using insertion sort which
+ // is well suited for small and already sorted arrays
+ // for big arrays, it could be better to use mergesort
+ const ssize_t count = size();
+ if (count > 1) {
+ void* array = const_cast<void*>(arrayImpl());
+ void* temp = nullptr;
+ ssize_t i = 1;
+ while (i < count) {
+ void* item = reinterpret_cast<char*>(array) + mItemSize*(i);
+ void* curr = reinterpret_cast<char*>(array) + mItemSize*(i-1);
+ if (cmp(curr, item, state) > 0) {
+
+ if (!temp) {
+ // we're going to have to modify the array...
+ array = editArrayImpl();
+ if (!array) return NO_MEMORY;
+ temp = malloc(mItemSize);
+ if (!temp) return NO_MEMORY;
+ item = reinterpret_cast<char*>(array) + mItemSize*(i);
+ curr = reinterpret_cast<char*>(array) + mItemSize*(i-1);
+ } else {
+ _do_destroy(temp, 1);
+ }
+
+ _do_copy(temp, item, 1);
+
+ ssize_t j = i-1;
+ void* next = reinterpret_cast<char*>(array) + mItemSize*(i);
+ do {
+ _do_destroy(next, 1);
+ _do_copy(next, curr, 1);
+ next = curr;
+ --j;
+ curr = nullptr;
+ if (j >= 0) {
+ curr = reinterpret_cast<char*>(array) + mItemSize*(j);
+ }
+ } while (j>=0 && (cmp(curr, temp, state) > 0));
+
+ _do_destroy(next, 1);
+ _do_copy(next, temp, 1);
+ }
+ i++;
+ }
+
+ if (temp) {
+ _do_destroy(temp, 1);
+ free(temp);
+ }
+ }
+ return OK;
+}
+
+void VectorImpl::pop()
+{
+ if (size())
+ removeItemsAt(size()-1, 1);
+}
+
+void VectorImpl::push()
+{
+ push(nullptr);
+}
+
+void VectorImpl::push(const void* item)
+{
+ insertAt(item, size());
+}
+
+ssize_t VectorImpl::add()
+{
+ return add(nullptr);
+}
+
+ssize_t VectorImpl::add(const void* item)
+{
+ return insertAt(item, size());
+}
+
+ssize_t VectorImpl::replaceAt(size_t index)
+{
+ return replaceAt(nullptr, index);
+}
+
+ssize_t VectorImpl::replaceAt(const void* prototype, size_t index)
+{
+ ALOG_ASSERT(index<size(),
+ "[%p] replace: index=%d, size=%d", this, (int)index, (int)size());
+
+ if (index >= size()) {
+ return BAD_INDEX;
+ }
+
+ void* item = editItemLocation(index);
+ if (item != prototype) {
+ if (item == nullptr)
+ return NO_MEMORY;
+ _do_destroy(item, 1);
+ if (prototype == nullptr) {
+ _do_construct(item, 1);
+ } else {
+ _do_copy(item, prototype, 1);
+ }
+ }
+ return ssize_t(index);
+}
+
+ssize_t VectorImpl::removeItemsAt(size_t index, size_t count)
+{
+ size_t end;
+ LOG_ALWAYS_FATAL_IF(__builtin_add_overflow(index, count, &end), "overflow: index=%zu count=%zu",
+ index, count);
+ if (end > size()) return BAD_VALUE;
+ _shrink(index, count);
+ return index;
+}
+
+void VectorImpl::finish_vector()
+{
+ release_storage();
+ mStorage = nullptr;
+ mCount = 0;
+}
+
+void VectorImpl::clear()
+{
+ _shrink(0, mCount);
+}
+
+void* VectorImpl::editItemLocation(size_t index)
+{
+ ALOG_ASSERT(index<capacity(),
+ "[%p] editItemLocation: index=%d, capacity=%d, count=%d",
+ this, (int)index, (int)capacity(), (int)mCount);
+
+ if (index < capacity()) {
+ void* buffer = editArrayImpl();
+ if (buffer) {
+ return reinterpret_cast<char*>(buffer) + index*mItemSize;
+ }
+ }
+ return nullptr;
+}
+
+const void* VectorImpl::itemLocation(size_t index) const
+{
+ ALOG_ASSERT(index<capacity(),
+ "[%p] itemLocation: index=%d, capacity=%d, count=%d",
+ this, (int)index, (int)capacity(), (int)mCount);
+
+ if (index < capacity()) {
+ const void* buffer = arrayImpl();
+ if (buffer) {
+ return reinterpret_cast<const char*>(buffer) + index*mItemSize;
+ }
+ }
+ return nullptr;
+}
+
+ssize_t VectorImpl::setCapacity(size_t new_capacity)
+{
+ // The capacity must always be greater than or equal to the size
+ // of this vector.
+ if (new_capacity <= size()) {
+ return capacity();
+ }
+
+ size_t new_allocation_size = 0;
+ LOG_ALWAYS_FATAL_IF(__builtin_mul_overflow(new_capacity, mItemSize, &new_allocation_size));
+ SharedBuffer* sb = SharedBuffer::alloc(new_allocation_size);
+ if (sb) {
+ void* array = sb->data();
+ _do_copy(array, mStorage, size());
+ release_storage();
+ mStorage = const_cast<void*>(array);
+ } else {
+ return NO_MEMORY;
+ }
+ return new_capacity;
+}
+
+ssize_t VectorImpl::resize(size_t size) {
+ ssize_t result = OK;
+ if (size > mCount) {
+ result = insertAt(mCount, size - mCount);
+ } else if (size < mCount) {
+ result = removeItemsAt(size, mCount - size);
+ }
+ return result < 0 ? result : size;
+}
+
+void VectorImpl::release_storage()
+{
+ if (mStorage) {
+ const SharedBuffer* sb = SharedBuffer::bufferFromData(mStorage);
+ if (sb->release(SharedBuffer::eKeepStorage) == 1) {
+ _do_destroy(mStorage, mCount);
+ SharedBuffer::dealloc(sb);
+ }
+ }
+}
+
+void* VectorImpl::_grow(size_t where, size_t amount)
+{
+// ALOGV("_grow(this=%p, where=%d, amount=%d) count=%d, capacity=%d",
+// this, (int)where, (int)amount, (int)mCount, (int)capacity());
+
+ ALOG_ASSERT(where <= mCount,
+ "[%p] _grow: where=%d, amount=%d, count=%d",
+ this, (int)where, (int)amount, (int)mCount); // caller already checked
+
+ size_t new_size;
+ LOG_ALWAYS_FATAL_IF(__builtin_add_overflow(mCount, amount, &new_size), "new_size overflow");
+
+ if (capacity() < new_size) {
+ // NOTE: This implementation used to resize vectors as per ((3*x + 1) / 2)
+ // (sigh..). Also note, the " + 1" was necessary to handle the special case
+ // where x == 1, where the resized_capacity will be equal to the old
+ // capacity without the +1. The old calculation wouldn't work properly
+ // if x was zero.
+ //
+ // This approximates the old calculation, using (x + (x/2) + 1) instead.
+ size_t new_capacity = 0;
+ LOG_ALWAYS_FATAL_IF(__builtin_add_overflow(new_size, (new_size / 2), &new_capacity),
+ "new_capacity overflow");
+ LOG_ALWAYS_FATAL_IF(
+ __builtin_add_overflow(new_capacity, static_cast<size_t>(1u), &new_capacity),
+ "new_capacity overflow");
+ new_capacity = max(kMinVectorCapacity, new_capacity);
+
+ size_t new_alloc_size = 0;
+ LOG_ALWAYS_FATAL_IF(__builtin_mul_overflow(new_capacity, mItemSize, &new_alloc_size),
+ "new_alloc_size overflow");
+
+ // ALOGV("grow vector %p, new_capacity=%d", this, (int)new_capacity);
+ if ((mStorage) &&
+ (mCount==where) &&
+ (mFlags & HAS_TRIVIAL_COPY) &&
+ (mFlags & HAS_TRIVIAL_DTOR))
+ {
+ const SharedBuffer* cur_sb = SharedBuffer::bufferFromData(mStorage);
+ SharedBuffer* sb = cur_sb->editResize(new_alloc_size);
+ if (sb) {
+ mStorage = sb->data();
+ } else {
+ return nullptr;
+ }
+ } else {
+ SharedBuffer* sb = SharedBuffer::alloc(new_alloc_size);
+ if (sb) {
+ void* array = sb->data();
+ if (where != 0) {
+ _do_copy(array, mStorage, where);
+ }
+ if (where != mCount) {
+ const void* from = reinterpret_cast<const uint8_t *>(mStorage) + where*mItemSize;
+ void* dest = reinterpret_cast<uint8_t *>(array) + (where+amount)*mItemSize;
+ _do_copy(dest, from, mCount-where);
+ }
+ release_storage();
+ mStorage = const_cast<void*>(array);
+ } else {
+ return nullptr;
+ }
+ }
+ } else {
+ void* array = editArrayImpl();
+ if (where != mCount) {
+ const void* from = reinterpret_cast<const uint8_t *>(array) + where*mItemSize;
+ void* to = reinterpret_cast<uint8_t *>(array) + (where+amount)*mItemSize;
+ _do_move_forward(to, from, mCount - where);
+ }
+ }
+ mCount = new_size;
+ void* free_space = const_cast<void*>(itemLocation(where));
+ return free_space;
+}
+
+void VectorImpl::_shrink(size_t where, size_t amount)
+{
+ if (!mStorage)
+ return;
+
+// ALOGV("_shrink(this=%p, where=%d, amount=%d) count=%d, capacity=%d",
+// this, (int)where, (int)amount, (int)mCount, (int)capacity());
+
+ ALOG_ASSERT(where + amount <= mCount,
+ "[%p] _shrink: where=%d, amount=%d, count=%d",
+ this, (int)where, (int)amount, (int)mCount); // caller already checked
+
+ size_t new_size;
+ LOG_ALWAYS_FATAL_IF(__builtin_sub_overflow(mCount, amount, &new_size));
+
+ if (new_size < (capacity() / 2)) {
+ // NOTE: (new_size * 2) is safe because capacity didn't overflow and
+ // new_size < (capacity / 2)).
+ const size_t new_capacity = max(kMinVectorCapacity, new_size * 2);
+
+ // NOTE: (new_capacity * mItemSize), (where * mItemSize) and
+ // ((where + amount) * mItemSize) beyond this point are safe because
+ // we are always reducing the capacity of the underlying SharedBuffer.
+ // In other words, (old_capacity * mItemSize) did not overflow, and
+ // where < (where + amount) < new_capacity < old_capacity.
+ if ((where == new_size) &&
+ (mFlags & HAS_TRIVIAL_COPY) &&
+ (mFlags & HAS_TRIVIAL_DTOR))
+ {
+ const SharedBuffer* cur_sb = SharedBuffer::bufferFromData(mStorage);
+ SharedBuffer* sb = cur_sb->editResize(new_capacity * mItemSize);
+ if (sb) {
+ mStorage = sb->data();
+ } else {
+ return;
+ }
+ } else {
+ SharedBuffer* sb = SharedBuffer::alloc(new_capacity * mItemSize);
+ if (sb) {
+ void* array = sb->data();
+ if (where != 0) {
+ _do_copy(array, mStorage, where);
+ }
+ if (where != new_size) {
+ const void* from = reinterpret_cast<const uint8_t *>(mStorage) + (where+amount)*mItemSize;
+ void* dest = reinterpret_cast<uint8_t *>(array) + where*mItemSize;
+ _do_copy(dest, from, new_size - where);
+ }
+ release_storage();
+ mStorage = const_cast<void*>(array);
+ } else{
+ return;
+ }
+ }
+ } else {
+ void* array = editArrayImpl();
+ void* to = reinterpret_cast<uint8_t *>(array) + where*mItemSize;
+ _do_destroy(to, amount);
+ if (where != new_size) {
+ const void* from = reinterpret_cast<uint8_t *>(array) + (where+amount)*mItemSize;
+ _do_move_backward(to, from, new_size - where);
+ }
+ }
+ mCount = new_size;
+}
+
+size_t VectorImpl::itemSize() const {
+ return mItemSize;
+}
+
+void VectorImpl::_do_construct(void* storage, size_t num) const
+{
+ if (!(mFlags & HAS_TRIVIAL_CTOR)) {
+ do_construct(storage, num);
+ }
+}
+
+void VectorImpl::_do_destroy(void* storage, size_t num) const
+{
+ if (!(mFlags & HAS_TRIVIAL_DTOR)) {
+ do_destroy(storage, num);
+ }
+}
+
+void VectorImpl::_do_copy(void* dest, const void* from, size_t num) const
+{
+ if (!(mFlags & HAS_TRIVIAL_COPY)) {
+ do_copy(dest, from, num);
+ } else {
+ memcpy(dest, from, num*itemSize());
+ }
+}
+
+void VectorImpl::_do_splat(void* dest, const void* item, size_t num) const {
+ do_splat(dest, item, num);
+}
+
+void VectorImpl::_do_move_forward(void* dest, const void* from, size_t num) const {
+ do_move_forward(dest, from, num);
+}
+
+void VectorImpl::_do_move_backward(void* dest, const void* from, size_t num) const {
+ do_move_backward(dest, from, num);
+}
+
+/*****************************************************************************/
+
+SortedVectorImpl::SortedVectorImpl(size_t itemSize, uint32_t flags)
+ : VectorImpl(itemSize, flags)
+{
+}
+
+SortedVectorImpl::SortedVectorImpl(const VectorImpl& rhs)
+: VectorImpl(rhs)
+{
+}
+
+SortedVectorImpl::~SortedVectorImpl()
+{
+}
+
+SortedVectorImpl& SortedVectorImpl::operator = (const SortedVectorImpl& rhs)
+{
+ return static_cast<SortedVectorImpl&>( VectorImpl::operator = (static_cast<const VectorImpl&>(rhs)) );
+}
+
+ssize_t SortedVectorImpl::indexOf(const void* item) const
+{
+ return _indexOrderOf(item);
+}
+
+size_t SortedVectorImpl::orderOf(const void* item) const
+{
+ size_t o;
+ _indexOrderOf(item, &o);
+ return o;
+}
+
+ssize_t SortedVectorImpl::_indexOrderOf(const void* item, size_t* order) const
+{
+ if (order) *order = 0;
+ if (isEmpty()) {
+ return NAME_NOT_FOUND;
+ }
+ // binary search
+ ssize_t err = NAME_NOT_FOUND;
+ ssize_t l = 0;
+ ssize_t h = size()-1;
+ ssize_t mid;
+ const void* a = arrayImpl();
+ const size_t s = itemSize();
+ while (l <= h) {
+ mid = l + (h - l)/2;
+ const void* const curr = reinterpret_cast<const char *>(a) + (mid*s);
+ const int c = do_compare(curr, item);
+ if (c == 0) {
+ err = l = mid;
+ break;
+ } else if (c < 0) {
+ l = mid + 1;
+ } else {
+ h = mid - 1;
+ }
+ }
+ if (order) *order = l;
+ return err;
+}
+
+ssize_t SortedVectorImpl::add(const void* item)
+{
+ size_t order;
+ ssize_t index = _indexOrderOf(item, &order);
+ if (index < 0) {
+ index = VectorImpl::insertAt(item, order, 1);
+ } else {
+ index = VectorImpl::replaceAt(item, index);
+ }
+ return index;
+}
+
+ssize_t SortedVectorImpl::merge(const VectorImpl& vector)
+{
+ // naive merge...
+ if (!vector.isEmpty()) {
+ const void* buffer = vector.arrayImpl();
+ const size_t is = itemSize();
+ size_t s = vector.size();
+ for (size_t i=0 ; i<s ; i++) {
+ ssize_t err = add( reinterpret_cast<const char*>(buffer) + i*is );
+ if (err<0) {
+ return err;
+ }
+ }
+ }
+ return OK;
+}
+
+ssize_t SortedVectorImpl::merge(const SortedVectorImpl& vector)
+{
+ // we've merging a sorted vector... nice!
+ ssize_t err = OK;
+ if (!vector.isEmpty()) {
+ // first take care of the case where the vectors are sorted together
+ if (do_compare(vector.itemLocation(vector.size()-1), arrayImpl()) <= 0) {
+ err = VectorImpl::insertVectorAt(static_cast<const VectorImpl&>(vector), 0);
+ } else if (do_compare(vector.arrayImpl(), itemLocation(size()-1)) >= 0) {
+ err = VectorImpl::appendVector(static_cast<const VectorImpl&>(vector));
+ } else {
+ // this could be made a little better
+ err = merge(static_cast<const VectorImpl&>(vector));
+ }
+ }
+ return err;
+}
+
+ssize_t SortedVectorImpl::remove(const void* item)
+{
+ ssize_t i = indexOf(item);
+ if (i>=0) {
+ VectorImpl::removeItemsAt(i, 1);
+ }
+ return i;
+}
+
+/*****************************************************************************/
+
+}; // namespace android
diff --git a/libutils/binder/Vector_benchmark.cpp b/libutils/binder/Vector_benchmark.cpp
new file mode 100644
index 0000000..c23d499
--- /dev/null
+++ b/libutils/binder/Vector_benchmark.cpp
@@ -0,0 +1,53 @@
+/*
+ * 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 <benchmark/benchmark.h>
+#include <utils/Vector.h>
+#include <vector>
+
+void BM_fill_android_vector(benchmark::State& state) {
+ android::Vector<char> v;
+ while (state.KeepRunning()) {
+ v.push('A');
+ }
+}
+BENCHMARK(BM_fill_android_vector);
+
+void BM_fill_std_vector(benchmark::State& state) {
+ std::vector<char> v;
+ while (state.KeepRunning()) {
+ v.push_back('A');
+ }
+}
+BENCHMARK(BM_fill_std_vector);
+
+void BM_prepend_android_vector(benchmark::State& state) {
+ android::Vector<char> v;
+ while (state.KeepRunning()) {
+ v.insertAt('A', 0);
+ }
+}
+BENCHMARK(BM_prepend_android_vector);
+
+void BM_prepend_std_vector(benchmark::State& state) {
+ std::vector<char> v;
+ while (state.KeepRunning()) {
+ v.insert(v.begin(), 'A');
+ }
+}
+BENCHMARK(BM_prepend_std_vector);
+
+BENCHMARK_MAIN();
diff --git a/libutils/binder/Vector_fuzz.cpp b/libutils/binder/Vector_fuzz.cpp
new file mode 100644
index 0000000..3cef487
--- /dev/null
+++ b/libutils/binder/Vector_fuzz.cpp
@@ -0,0 +1,215 @@
+/*
+ * Copyright 2020 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 <fuzzer/FuzzedDataProvider.h>
+#include <log/log.h>
+#include <utils/Vector.h>
+
+#include <functional>
+
+using android::Vector;
+
+static constexpr uint16_t MAX_VEC_SIZE = 100;
+static constexpr bool kLog = false;
+
+struct NonTrivialDestructor {
+ NonTrivialDestructor() : mInit(1) {}
+ ~NonTrivialDestructor() {
+ LOG_ALWAYS_FATAL_IF(mInit != 1, "mInit should be 1, but it's: %d", mInit);
+ mInit--;
+ LOG_ALWAYS_FATAL_IF(mInit != 0, "mInit should be 0, but it's: %d", mInit);
+ }
+
+ private:
+ uint8_t mInit;
+};
+
+template <typename T>
+struct VectorFuzzerData {
+ Vector<T> vector;
+ const std::vector<std::function<void(FuzzedDataProvider&, Vector<T>&)>> funcs = {
+ [&](FuzzedDataProvider& provider, Vector<T>& vector) {
+ (void)provider;
+ // operator= Vector<TYPE>, still needs for SortedVector
+ if (kLog) ALOGI("operator=");
+ vector = testVector(provider);
+ },
+ [&](FuzzedDataProvider& provider, Vector<T>& vector) {
+ (void)provider;
+ if (kLog) ALOGI("clear");
+ vector.clear();
+ },
+ [&](FuzzedDataProvider& provider, Vector<T>& vector) {
+ (void)provider;
+ if (kLog) ALOGI("size");
+ vector.size();
+ },
+ [&](FuzzedDataProvider& provider, Vector<T>& vector) {
+ (void)provider;
+ if (kLog) ALOGI("isEmpty");
+ vector.isEmpty();
+ },
+ [&](FuzzedDataProvider& provider, Vector<T>& vector) {
+ (void)provider;
+ if (kLog) ALOGI("capacity");
+ vector.capacity();
+ },
+ [&](FuzzedDataProvider& provider, Vector<T>& vector) {
+ size_t vectorSize = provider.ConsumeIntegralInRange<size_t>(0, MAX_VEC_SIZE);
+ if (kLog) ALOGI("setCapacity");
+ vector.setCapacity(vectorSize);
+ },
+ [&](FuzzedDataProvider& provider, Vector<T>& vector) {
+ size_t vectorSize = provider.ConsumeIntegralInRange<size_t>(0, MAX_VEC_SIZE);
+ if (kLog) ALOGI("resize");
+ vector.resize(vectorSize);
+ },
+ [&](FuzzedDataProvider& provider, Vector<T>& vector) {
+ (void)provider;
+ if (kLog) ALOGI("array");
+ vector.array();
+ },
+ [&](FuzzedDataProvider& provider, Vector<T>& vector) {
+ (void)provider;
+ if (kLog) ALOGI("editArray");
+ vector.editArray();
+ },
+ [&](FuzzedDataProvider& provider, Vector<T>& vector) {
+ if (vector.size() == 0) return;
+ size_t idx = provider.ConsumeIntegralInRange<size_t>(0, vector.size() - 1);
+ if (kLog) ALOGI("operator[]");
+ vector[idx]; // returns a const value for Vector
+ },
+ [&](FuzzedDataProvider& provider, Vector<T>& vector) {
+ if (vector.size() == 0) return;
+ size_t idx = provider.ConsumeIntegralInRange<size_t>(0, vector.size() - 1);
+ if (kLog) ALOGI("itemAt");
+ vector.itemAt(idx);
+ },
+ [&](FuzzedDataProvider& provider, Vector<T>& vector) {
+ (void)provider;
+ if (vector.size() == 0) return;
+ if (kLog) ALOGI("top");
+ vector.top();
+ },
+ [&](FuzzedDataProvider& provider, Vector<T>& vector) {
+ if (vector.size() == 0) return;
+ size_t idx = provider.ConsumeIntegralInRange<size_t>(0, vector.size() - 1);
+ if (kLog) ALOGI("editItemAt");
+ vector.editItemAt(idx);
+ },
+ [&](FuzzedDataProvider& provider, Vector<T>& vector) {
+ (void)provider;
+ if (vector.size() == 0) return;
+ if (kLog) ALOGI("editTop");
+ vector.editTop() = T{};
+ },
+ [&](FuzzedDataProvider& provider, Vector<T>& vector) {
+ uint8_t idx = provider.ConsumeIntegralInRange<uint8_t>(0, vector.size());
+ Vector vec2 = testVector(provider);
+ if (vec2.size() == 0) return; // TODO: maybe we should support this?
+ if (kLog) ALOGI("insertVectorAt %d of size %zu", idx, vec2.size());
+ vector.insertVectorAt(vec2, idx);
+ },
+ [&](FuzzedDataProvider& provider, Vector<T>& vector) {
+ if (kLog) ALOGI("appendVector");
+ vector.appendVector(testVector(provider));
+ },
+ // TODO: insertArrayAt
+ // TODO: appendArray
+ [&](FuzzedDataProvider& provider, Vector<T>& vector) {
+ uint8_t idx = provider.ConsumeIntegralInRange<uint8_t>(0, vector.size());
+ uint8_t numItems = provider.ConsumeIntegralInRange<uint8_t>(1, 100);
+ if (kLog) ALOGI("insertAt");
+ vector.insertAt(idx, numItems);
+ },
+ [&](FuzzedDataProvider& provider, Vector<T>& vector) {
+ uint8_t idx = provider.ConsumeIntegralInRange<uint8_t>(0, vector.size());
+ uint8_t numItems = provider.ConsumeIntegralInRange<uint8_t>(1, 100);
+ if (kLog) ALOGI("insertAt");
+ vector.insertAt(T{}, idx, numItems);
+ },
+ [&](FuzzedDataProvider& provider, Vector<T>& vector) {
+ (void)provider;
+ if (vector.size() == 0) return;
+ if (kLog) ALOGI("pop");
+ vector.pop();
+ },
+ [&](FuzzedDataProvider& provider, Vector<T>& vector) {
+ (void)provider;
+ if (kLog) ALOGI("push");
+ vector.push();
+ },
+ [&](FuzzedDataProvider& provider, Vector<T>& vector) {
+ (void)provider;
+ if (kLog) ALOGI("add");
+ vector.add();
+ },
+ [&](FuzzedDataProvider& provider, Vector<T>& vector) {
+ (void)provider;
+ if (kLog) ALOGI("add");
+ vector.add(T{});
+ },
+ [&](FuzzedDataProvider& provider, Vector<T>& vector) {
+ uint8_t idx = provider.ConsumeIntegralInRange<uint8_t>(0, vector.size() - 1);
+ if (kLog) ALOGI("replaceAt");
+ vector.replaceAt(idx);
+ },
+ [&](FuzzedDataProvider& provider, Vector<T>& vector) {
+ uint8_t idx = provider.ConsumeIntegralInRange<uint8_t>(0, vector.size() - 1);
+ if (kLog) ALOGI("replaceAt");
+ vector.replaceAt(T{}, idx);
+ },
+ [&](FuzzedDataProvider& provider, Vector<T>& vector) {
+ if (vector.size() == 0) return;
+ uint8_t idx = provider.ConsumeIntegralInRange<uint8_t>(0, vector.size() - 1);
+ if (kLog) ALOGI("remoteItemsAt");
+ vector.removeItemsAt(idx); // TODO: different count
+ },
+ // removeAt is alias for removeItemsAt
+ // TODO: sort
+ [&](FuzzedDataProvider& provider, Vector<T>& vector) {
+ (void)provider;
+ if (kLog) ALOGI("getItemSize");
+ vector.getItemSize();
+ },
+ // TODO: iterators
+ };
+
+ Vector<T> testVector(FuzzedDataProvider& provider) {
+ Vector<T> vec;
+ size_t vectorSize = provider.ConsumeIntegralInRange<size_t>(0, MAX_VEC_SIZE);
+ return vec;
+ }
+
+ void fuzz(FuzzedDataProvider&& provider) {
+ while (provider.remaining_bytes()) {
+ size_t funcIdx = provider.ConsumeIntegralInRange<size_t>(0, funcs.size() - 1);
+ funcs[funcIdx](provider, vector);
+ }
+ }
+};
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+ FuzzedDataProvider provider(data, size);
+
+ provider.PickValueInArray<std::function<void()>>({
+ [&]() { VectorFuzzerData<uint8_t>().fuzz(std::move(provider)); },
+ [&]() { VectorFuzzerData<int32_t>().fuzz(std::move(provider)); },
+ [&]() { VectorFuzzerData<NonTrivialDestructor>().fuzz(std::move(provider)); },
+ })();
+
+ return 0;
+}
diff --git a/libutils/binder/Vector_test.cpp b/libutils/binder/Vector_test.cpp
new file mode 100644
index 0000000..6d90eaa
--- /dev/null
+++ b/libutils/binder/Vector_test.cpp
@@ -0,0 +1,148 @@
+/*
+ * Copyright (C) 2012 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.
+ */
+
+#define LOG_TAG "Vector_test"
+
+#define __STDC_LIMIT_MACROS
+#include <stdint.h>
+#include <unistd.h>
+
+#include <android/log.h>
+#include <gtest/gtest.h>
+#include <utils/Vector.h>
+
+namespace android {
+
+class VectorTest : public testing::Test {
+protected:
+ virtual void SetUp() {
+ }
+
+ virtual void TearDown() {
+ }
+
+public:
+};
+
+
+TEST_F(VectorTest, CopyOnWrite_CopyAndAddElements) {
+
+ Vector<int> vector;
+ Vector<int> other;
+ vector.setCapacity(8);
+
+ vector.add(1);
+ vector.add(2);
+ vector.add(3);
+
+ EXPECT_EQ(3U, vector.size());
+
+ // copy the vector
+ other = vector;
+
+ EXPECT_EQ(3U, other.size());
+
+ // add an element to the first vector
+ vector.add(4);
+
+ // make sure the sizes are correct
+ EXPECT_EQ(4U, vector.size());
+ EXPECT_EQ(3U, other.size());
+
+ // add an element to the copy
+ other.add(5);
+
+ // make sure the sizes are correct
+ EXPECT_EQ(4U, vector.size());
+ EXPECT_EQ(4U, other.size());
+
+ // make sure the content of both vectors are correct
+ EXPECT_EQ(vector[3], 4);
+ EXPECT_EQ(other[3], 5);
+}
+
+TEST_F(VectorTest, SetCapacity_Overflow) {
+ Vector<int> vector;
+ EXPECT_DEATH(vector.setCapacity(SIZE_MAX / sizeof(int) + 1), "Assertion failed");
+}
+
+TEST_F(VectorTest, SetCapacity_ShrinkBelowSize) {
+ Vector<int> vector;
+ vector.add(1);
+ vector.add(2);
+ vector.add(3);
+ vector.add(4);
+
+ vector.setCapacity(8);
+ ASSERT_EQ(8U, vector.capacity());
+ vector.setCapacity(2);
+ ASSERT_EQ(8U, vector.capacity());
+}
+
+TEST_F(VectorTest, _grow_OverflowSize) {
+ Vector<int> vector;
+ vector.add(1);
+
+ // Checks that the size calculation (not the capacity calculation) doesn't
+ // overflow : the size here will be (1 + SIZE_MAX).
+ EXPECT_DEATH(vector.insertArrayAt(nullptr, 0, SIZE_MAX), "new_size overflow");
+}
+
+TEST_F(VectorTest, _grow_OverflowCapacityDoubling) {
+ Vector<int> vector;
+
+ // This should fail because the calculated capacity will overflow even though
+ // the size of the vector doesn't.
+ EXPECT_DEATH(vector.insertArrayAt(nullptr, 0, (SIZE_MAX - 1)), "new_capacity overflow");
+}
+
+TEST_F(VectorTest, _grow_OverflowBufferAlloc) {
+ Vector<int> vector;
+ // This should fail because the capacity * sizeof(int) overflows, even
+ // though the capacity itself doesn't.
+ EXPECT_DEATH(vector.insertArrayAt(nullptr, 0, (SIZE_MAX / 2)), "new_alloc_size overflow");
+}
+
+TEST_F(VectorTest, editArray_Shared) {
+ Vector<int> vector1;
+ vector1.add(1);
+ vector1.add(2);
+ vector1.add(3);
+ vector1.add(4);
+
+ Vector<int> vector2 = vector1;
+ ASSERT_EQ(vector1.array(), vector2.array());
+ // We must make a copy here, since we're not the exclusive owners
+ // of this array.
+ ASSERT_NE(vector1.editArray(), vector2.editArray());
+
+ // Vector doesn't implement operator ==.
+ ASSERT_EQ(vector1.size(), vector2.size());
+ for (size_t i = 0; i < vector1.size(); ++i) {
+ EXPECT_EQ(vector1[i], vector2[i]);
+ }
+}
+
+TEST_F(VectorTest, removeItemsAt_overflow) {
+ android::Vector<int> v;
+ for (int i = 0; i < 666; i++) v.add(i);
+
+ ASSERT_DEATH(v.removeItemsAt(SIZE_MAX, 666), "overflow");
+ ASSERT_DEATH(v.removeItemsAt(666, SIZE_MAX), "overflow");
+ ASSERT_DEATH(v.removeItemsAt(SIZE_MAX, SIZE_MAX), "overflow");
+}
+
+} // namespace android
diff --git a/libutils/binder/include/utils/Errors.h b/libutils/binder/include/utils/Errors.h
new file mode 100644
index 0000000..22fb36d
--- /dev/null
+++ b/libutils/binder/include/utils/Errors.h
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2007 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 <errno.h>
+#include <stdint.h>
+#include <sys/types.h>
+#include <string>
+
+namespace android {
+
+/**
+ * The type used to return success/failure from frameworks APIs.
+ * See the anonymous enum below for valid values.
+ */
+typedef int32_t status_t;
+
+/*
+ * Error codes.
+ * All error codes are negative values.
+ */
+
+enum {
+ OK = 0, // Preferred constant for checking success.
+#ifndef NO_ERROR
+ // Win32 #defines NO_ERROR as well. It has the same value, so there's no
+ // real conflict, though it's a bit awkward.
+ NO_ERROR = OK, // Deprecated synonym for `OK`. Prefer `OK` because it doesn't conflict with Windows.
+#endif
+
+ UNKNOWN_ERROR = (-2147483647-1), // INT32_MIN value
+
+ NO_MEMORY = -ENOMEM,
+ INVALID_OPERATION = -ENOSYS,
+ BAD_VALUE = -EINVAL,
+ BAD_TYPE = (UNKNOWN_ERROR + 1),
+ NAME_NOT_FOUND = -ENOENT,
+ PERMISSION_DENIED = -EPERM,
+ NO_INIT = -ENODEV,
+ ALREADY_EXISTS = -EEXIST,
+ DEAD_OBJECT = -EPIPE,
+ FAILED_TRANSACTION = (UNKNOWN_ERROR + 2),
+#if !defined(_WIN32)
+ BAD_INDEX = -EOVERFLOW,
+ NOT_ENOUGH_DATA = -ENODATA,
+ WOULD_BLOCK = -EWOULDBLOCK,
+ TIMED_OUT = -ETIMEDOUT,
+ UNKNOWN_TRANSACTION = -EBADMSG,
+#else
+ BAD_INDEX = -E2BIG,
+ NOT_ENOUGH_DATA = (UNKNOWN_ERROR + 3),
+ WOULD_BLOCK = (UNKNOWN_ERROR + 4),
+ TIMED_OUT = (UNKNOWN_ERROR + 5),
+ UNKNOWN_TRANSACTION = (UNKNOWN_ERROR + 6),
+#endif
+ FDS_NOT_ALLOWED = (UNKNOWN_ERROR + 7),
+ UNEXPECTED_NULL = (UNKNOWN_ERROR + 8),
+};
+
+// Human readable name of error
+std::string statusToString(status_t status);
+
+} // namespace android
diff --git a/libutils/binder/include/utils/RefBase.h b/libutils/binder/include/utils/RefBase.h
new file mode 100644
index 0000000..5e3fa7d
--- /dev/null
+++ b/libutils/binder/include/utils/RefBase.h
@@ -0,0 +1,819 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+
+// SOME COMMENTS ABOUT USAGE:
+
+// This provides primarily wp<> weak pointer types and RefBase, which work
+// together with sp<> from <StrongPointer.h>.
+
+// sp<> (and wp<>) are a type of smart pointer that use a well defined protocol
+// to operate. As long as the object they are templated with implements that
+// protocol, these smart pointers work. In several places the platform
+// instantiates sp<> with non-RefBase objects; the two are not tied to each
+// other.
+
+// RefBase is such an implementation and it supports strong pointers, weak
+// pointers and some magic features for the binder.
+
+// So, when using RefBase objects, you have the ability to use strong and weak
+// pointers through sp<> and wp<>.
+
+// Normally, when the last strong pointer goes away, the object is destroyed,
+// i.e. it's destructor is called. HOWEVER, parts of its associated memory is not
+// freed until the last weak pointer is released.
+
+// Weak pointers are essentially "safe" pointers. They are always safe to
+// access through promote(). They may return nullptr if the object was
+// destroyed because it ran out of strong pointers. This makes them good candidates
+// for keys in a cache for instance.
+
+// Weak pointers remain valid for comparison purposes even after the underlying
+// object has been destroyed. Even if object A is destroyed and its memory reused
+// for B, A remaining weak pointer to A will not compare equal to one to B.
+// This again makes them attractive for use as keys.
+
+// How is this supposed / intended to be used?
+
+// Our recommendation is to use strong references (sp<>) when there is an
+// ownership relation. e.g. when an object "owns" another one, use a strong
+// ref. And of course use strong refs as arguments of functions (it's extremely
+// rare that a function will take a wp<>).
+
+// Typically a newly allocated object will immediately be used to initialize
+// a strong pointer, which may then be used to construct or assign to other
+// strong and weak pointers.
+
+// Use weak references when there are no ownership relation. e.g. the keys in a
+// cache (you cannot use plain pointers because there is no safe way to acquire
+// a strong reference from a vanilla pointer).
+
+// This implies that two objects should never (or very rarely) have sp<> on
+// each other, because they can't both own each other.
+
+
+// Caveats with reference counting
+
+// Obviously, circular strong references are a big problem; this creates leaks
+// and it's hard to debug -- except it's in fact really easy because RefBase has
+// tons of debugging code for that. It can basically tell you exactly where the
+// leak is.
+
+// Another problem has to do with destructors with side effects. You must
+// assume that the destructor of reference counted objects can be called AT ANY
+// TIME. For instance code as simple as this:
+
+// void setStuff(const sp<Stuff>& stuff) {
+// std::lock_guard<std::mutex> lock(mMutex);
+// mStuff = stuff;
+// }
+
+// is very dangerous. This code WILL deadlock one day or another.
+
+// What isn't obvious is that ~Stuff() can be called as a result of the
+// assignment. And it gets called with the lock held. First of all, the lock is
+// protecting mStuff, not ~Stuff(). Secondly, if ~Stuff() uses its own internal
+// mutex, now you have mutex ordering issues. Even worse, if ~Stuff() is
+// virtual, now you're calling into "user" code (potentially), by that, I mean,
+// code you didn't even write.
+
+// A correct way to write this code is something like:
+
+// void setStuff(const sp<Stuff>& stuff) {
+// std::unique_lock<std::mutex> lock(mMutex);
+// sp<Stuff> hold = mStuff;
+// mStuff = stuff;
+// lock.unlock();
+// }
+
+// More importantly, reference counted objects should do as little work as
+// possible in their destructor, or at least be mindful that their destructor
+// could be called from very weird and unintended places.
+
+// Other more specific restrictions for wp<> and sp<>:
+
+// Do not construct a strong pointer to "this" in an object's constructor.
+// The onFirstRef() callback would be made on an incompletely constructed
+// object.
+// Construction of a weak pointer to "this" in an object's constructor is also
+// discouraged. But the implementation was recently changed so that, in the
+// absence of extendObjectLifetime() calls, weak pointers no longer impact
+// object lifetime, and hence this no longer risks premature deallocation,
+// and hence usually works correctly.
+
+// Such strong or weak pointers can be safely created in the RefBase onFirstRef()
+// callback.
+
+// Use of wp::unsafe_get() for any purpose other than debugging is almost
+// always wrong. Unless you somehow know that there is a longer-lived sp<> to
+// the same object, it may well return a pointer to a deallocated object that
+// has since been reallocated for a different purpose. (And if you know there
+// is a longer-lived sp<>, why not use an sp<> directly?) A wp<> should only be
+// dereferenced by using promote().
+
+// Any object inheriting from RefBase should always be destroyed as the result
+// of a reference count decrement, not via any other means. Such objects
+// should never be stack allocated, or appear directly as data members in other
+// objects. Objects inheriting from RefBase should have their strong reference
+// count incremented as soon as possible after construction. Usually this
+// will be done via construction of an sp<> to the object, but may instead
+// involve other means of calling RefBase::incStrong().
+// Explicitly deleting or otherwise destroying a RefBase object with outstanding
+// wp<> or sp<> pointers to it will result in an abort or heap corruption.
+
+// It is particularly important not to mix sp<> and direct storage management
+// since the sp from raw pointer constructor is implicit. Thus if a RefBase-
+// -derived object of type T is managed without ever incrementing its strong
+// count, and accidentally passed to f(sp<T>), a strong pointer to the object
+// will be temporarily constructed and destroyed, prematurely deallocating the
+// object, and resulting in heap corruption. None of this would be easily
+// visible in the source. See below on
+// ANDROID_UTILS_REF_BASE_DISABLE_IMPLICIT_CONSTRUCTION for a compile time
+// option which helps avoid this case.
+
+// Extra Features:
+
+// RefBase::extendObjectLifetime() can be used to prevent destruction of the
+// object while there are still weak references. This is really special purpose
+// functionality to support Binder.
+
+// Wp::promote(), implemented via the attemptIncStrong() member function, is
+// used to try to convert a weak pointer back to a strong pointer. It's the
+// normal way to try to access the fields of an object referenced only through
+// a wp<>. Binder code also sometimes uses attemptIncStrong() directly.
+
+// RefBase provides a number of additional callbacks for certain reference count
+// events, as well as some debugging facilities.
+
+// Debugging support can be enabled by turning on DEBUG_REFS in RefBase.cpp.
+// Otherwise little checking is provided.
+
+// Thread safety:
+
+// Like std::shared_ptr, sp<> and wp<> allow concurrent accesses to DIFFERENT
+// sp<> and wp<> instances that happen to refer to the same underlying object.
+// They do NOT support concurrent access (where at least one access is a write)
+// to THE SAME sp<> or wp<>. In effect, their thread-safety properties are
+// exactly like those of T*, NOT atomic<T*>.
+
+// Safety option: ANDROID_UTILS_REF_BASE_DISABLE_IMPLICIT_CONSTRUCTION
+//
+// This flag makes the semantics for using a RefBase object with wp<> and sp<>
+// much stricter by disabling implicit conversion from raw pointers to these
+// objects. In order to use this, apply this flag in Android.bp like so:
+//
+// cflags: [
+// "-DANDROID_UTILS_REF_BASE_DISABLE_IMPLICIT_CONSTRUCTION",
+// ],
+//
+// REGARDLESS of whether this flag is on, best usage of sp<> is shown below. If
+// this flag is on, no other usage is possible (directly calling RefBase methods
+// is possible, but seeing code using 'incStrong' instead of 'sp<>', for
+// instance, should already set off big alarm bells. With carefully constructed
+// data structures, it should NEVER be necessary to directly use RefBase
+// methods). Proper RefBase usage:
+//
+// class Foo : virtual public RefBase { ... };
+//
+// // always construct an sp object with sp::make
+// sp<Foo> myFoo = sp<Foo>::make(/*args*/);
+//
+// // if you need a weak pointer, it must be constructed from a strong
+// // pointer
+// wp<Foo> weakFoo = myFoo; // NOT myFoo.get()
+//
+// // If you are inside of a method of Foo and need access to a strong
+// // explicitly call this function. This documents your intention to code
+// // readers, and it will give a runtime error for what otherwise would
+// // be potential double ownership
+// .... Foo::someMethod(...) {
+// // asserts if there is a memory issue
+// sp<Foo> thiz = sp<Foo>::fromExisting(this);
+// }
+//
+
+#ifndef ANDROID_REF_BASE_H
+#define ANDROID_REF_BASE_H
+
+#include <atomic>
+#include <functional>
+#include <memory>
+#include <type_traits> // for common_type.
+
+#include <stdint.h>
+#include <sys/types.h>
+#include <stdlib.h>
+#include <string.h>
+
+// LightRefBase used to be declared in this header, so we have to include it
+#include <utils/LightRefBase.h>
+
+#include <utils/StrongPointer.h>
+#include <utils/TypeHelpers.h>
+
+// ---------------------------------------------------------------------------
+namespace android {
+
+// ---------------------------------------------------------------------------
+
+#define COMPARE_WEAK(_op_) \
+template<typename U> \
+inline bool operator _op_ (const U* o) const { \
+ return m_ptr _op_ o; \
+} \
+/* Needed to handle type inference for nullptr: */ \
+inline bool operator _op_ (const T* o) const { \
+ return m_ptr _op_ o; \
+}
+
+template<template<typename C> class comparator, typename T, typename U>
+static inline bool _wp_compare_(T* a, U* b) {
+ return comparator<typename std::common_type<T*, U*>::type>()(a, b);
+}
+
+// Use std::less and friends to avoid undefined behavior when ordering pointers
+// to different objects.
+#define COMPARE_WEAK_FUNCTIONAL(_op_, _compare_) \
+template<typename U> \
+inline bool operator _op_ (const U* o) const { \
+ return _wp_compare_<_compare_>(m_ptr, o); \
+}
+
+// ---------------------------------------------------------------------------
+
+// RefererenceRenamer is pure abstract, there is no virtual method
+// implementation to put in a translation unit in order to silence the
+// weak vtables warning.
+#if defined(__clang__)
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wweak-vtables"
+#endif
+
+class ReferenceRenamer {
+protected:
+ // destructor is purposely not virtual so we avoid code overhead from
+ // subclasses; we have to make it protected to guarantee that it
+ // cannot be called from this base class (and to make strict compilers
+ // happy).
+ ~ReferenceRenamer() { }
+public:
+ virtual void operator()(size_t i) const = 0;
+};
+
+#if defined(__clang__)
+#pragma clang diagnostic pop
+#endif
+
+// ---------------------------------------------------------------------------
+
+class RefBase
+{
+public:
+ void incStrong(const void* id) const;
+ void incStrongRequireStrong(const void* id) const;
+ void decStrong(const void* id) const;
+
+ void forceIncStrong(const void* id) const;
+
+ //! DEBUGGING ONLY: Get current strong ref count.
+ int32_t getStrongCount() const;
+
+ class weakref_type
+ {
+ public:
+ RefBase* refBase() const;
+
+ void incWeak(const void* id);
+ void incWeakRequireWeak(const void* id);
+ void decWeak(const void* id);
+
+ // acquires a strong reference if there is already one.
+ bool attemptIncStrong(const void* id);
+
+ // acquires a weak reference if there is already one.
+ // This is not always safe. see ProcessState.cpp and BpBinder.cpp
+ // for proper use.
+ bool attemptIncWeak(const void* id);
+
+ //! DEBUGGING ONLY: Get current weak ref count.
+ int32_t getWeakCount() const;
+
+ //! DEBUGGING ONLY: Print references held on object.
+ void printRefs() const;
+
+ //! DEBUGGING ONLY: Enable tracking for this object.
+ // enable -- enable/disable tracking
+ // retain -- when tracking is enable, if true, then we save a stack trace
+ // for each reference and dereference; when retain == false, we
+ // match up references and dereferences and keep only the
+ // outstanding ones.
+
+ void trackMe(bool enable, bool retain);
+ };
+
+ weakref_type* createWeak(const void* id) const;
+
+ weakref_type* getWeakRefs() const;
+
+ //! DEBUGGING ONLY: Print references held on object.
+ inline void printRefs() const { getWeakRefs()->printRefs(); }
+
+ //! DEBUGGING ONLY: Enable tracking of object.
+ inline void trackMe(bool enable, bool retain)
+ {
+ getWeakRefs()->trackMe(enable, retain);
+ }
+
+protected:
+ // When constructing these objects, prefer using sp::make<>. Using a RefBase
+ // object on the stack or with other refcount mechanisms (e.g.
+ // std::shared_ptr) is inherently wrong. RefBase types have an implicit
+ // ownership model and cannot be safely used with other ownership models.
+
+ RefBase();
+ virtual ~RefBase();
+
+ //! Flags for extendObjectLifetime()
+ enum {
+ OBJECT_LIFETIME_STRONG = 0x0000,
+ OBJECT_LIFETIME_WEAK = 0x0001,
+ OBJECT_LIFETIME_MASK = 0x0001
+ };
+
+ void extendObjectLifetime(int32_t mode);
+
+ //! Flags for onIncStrongAttempted()
+ enum {
+ FIRST_INC_STRONG = 0x0001
+ };
+
+ // Invoked after creation of initial strong pointer/reference.
+ virtual void onFirstRef();
+ // Invoked when either the last strong reference goes away, or we need to undo
+ // the effect of an unnecessary onIncStrongAttempted.
+ virtual void onLastStrongRef(const void* id);
+ // Only called in OBJECT_LIFETIME_WEAK case. Returns true if OK to promote to
+ // strong reference. May have side effects if it returns true.
+ // The first flags argument is always FIRST_INC_STRONG.
+ // TODO: Remove initial flag argument.
+ virtual bool onIncStrongAttempted(uint32_t flags, const void* id);
+ // Invoked in the OBJECT_LIFETIME_WEAK case when the last reference of either
+ // kind goes away. Unused.
+ // TODO: Remove.
+ virtual void onLastWeakRef(const void* id);
+
+private:
+ friend class weakref_type;
+ class weakref_impl;
+
+ RefBase(const RefBase& o);
+ RefBase& operator=(const RefBase& o);
+
+private:
+ friend class ReferenceMover;
+
+ static void renameRefs(size_t n, const ReferenceRenamer& renamer);
+
+ static void renameRefId(weakref_type* ref,
+ const void* old_id, const void* new_id);
+
+ static void renameRefId(RefBase* ref,
+ const void* old_id, const void* new_id);
+
+ weakref_impl* const mRefs;
+};
+
+// ---------------------------------------------------------------------------
+
+template <typename T>
+class wp
+{
+public:
+ typedef typename RefBase::weakref_type weakref_type;
+
+ inline wp() : m_ptr(nullptr), m_refs(nullptr) { }
+
+ // if nullptr, returns nullptr
+ //
+ // if a weak pointer is already available, this will retrieve it,
+ // otherwise, this will abort
+ static inline wp<T> fromExisting(T* other);
+
+ // for more information about this flag, see above
+#if defined(ANDROID_UTILS_REF_BASE_DISABLE_IMPLICIT_CONSTRUCTION)
+ wp(std::nullptr_t) : wp() {}
+#else
+ wp(T* other); // NOLINT(implicit)
+ template <typename U>
+ wp(U* other); // NOLINT(implicit)
+ wp& operator=(T* other);
+ template <typename U>
+ wp& operator=(U* other);
+#endif
+
+ wp(const wp<T>& other);
+ explicit wp(const sp<T>& other);
+
+ template<typename U> wp(const sp<U>& other); // NOLINT(implicit)
+ template<typename U> wp(const wp<U>& other); // NOLINT(implicit)
+
+ ~wp();
+
+ // Assignment
+
+ wp& operator = (const wp<T>& other);
+ wp& operator = (const sp<T>& other);
+
+ template<typename U> wp& operator = (const wp<U>& other);
+ template<typename U> wp& operator = (const sp<U>& other);
+
+ void set_object_and_refs(T* other, weakref_type* refs);
+
+ // promotion to sp
+
+ sp<T> promote() const;
+
+ // Reset
+
+ void clear();
+
+ // Accessors
+
+ inline weakref_type* get_refs() const { return m_refs; }
+
+ inline T* unsafe_get() const { return m_ptr; }
+
+ // Operators
+
+ COMPARE_WEAK(==)
+ COMPARE_WEAK(!=)
+ COMPARE_WEAK_FUNCTIONAL(>, std::greater)
+ COMPARE_WEAK_FUNCTIONAL(<, std::less)
+ COMPARE_WEAK_FUNCTIONAL(<=, std::less_equal)
+ COMPARE_WEAK_FUNCTIONAL(>=, std::greater_equal)
+
+ template<typename U>
+ inline bool operator == (const wp<U>& o) const {
+ return m_refs == o.m_refs; // Implies m_ptr == o.mptr; see invariants below.
+ }
+
+ template<typename U>
+ inline bool operator == (const sp<U>& o) const {
+ // Just comparing m_ptr fields is often dangerous, since wp<> may refer to an older
+ // object at the same address.
+ if (o == nullptr) {
+ return m_ptr == nullptr;
+ } else {
+ return m_refs == o->getWeakRefs(); // Implies m_ptr == o.mptr.
+ }
+ }
+
+ template<typename U>
+ inline bool operator != (const sp<U>& o) const {
+ return !(*this == o);
+ }
+
+ template<typename U>
+ inline bool operator > (const wp<U>& o) const {
+ if (m_ptr == o.m_ptr) {
+ return _wp_compare_<std::greater>(m_refs, o.m_refs);
+ } else {
+ return _wp_compare_<std::greater>(m_ptr, o.m_ptr);
+ }
+ }
+
+ template<typename U>
+ inline bool operator < (const wp<U>& o) const {
+ if (m_ptr == o.m_ptr) {
+ return _wp_compare_<std::less>(m_refs, o.m_refs);
+ } else {
+ return _wp_compare_<std::less>(m_ptr, o.m_ptr);
+ }
+ }
+ template<typename U> inline bool operator != (const wp<U>& o) const { return !operator == (o); }
+ template<typename U> inline bool operator <= (const wp<U>& o) const { return !operator > (o); }
+ template<typename U> inline bool operator >= (const wp<U>& o) const { return !operator < (o); }
+
+private:
+ template<typename Y> friend class sp;
+ template<typename Y> friend class wp;
+
+ T* m_ptr;
+ weakref_type* m_refs;
+};
+
+#undef COMPARE_WEAK
+#undef COMPARE_WEAK_FUNCTIONAL
+
+// ---------------------------------------------------------------------------
+// No user serviceable parts below here.
+
+// Implementation invariants:
+// Either
+// 1) m_ptr and m_refs are both null, or
+// 2) m_refs == m_ptr->mRefs, or
+// 3) *m_ptr is no longer live, and m_refs points to the weakref_type object that corresponded
+// to m_ptr while it was live. *m_refs remains live while a wp<> refers to it.
+//
+// The m_refs field in a RefBase object is allocated on construction, unique to that RefBase
+// object, and never changes. Thus if two wp's have identical m_refs fields, they are either both
+// null or point to the same object. If two wp's have identical m_ptr fields, they either both
+// point to the same live object and thus have the same m_ref fields, or at least one of the
+// objects is no longer live.
+//
+// Note that the above comparison operations go out of their way to provide an ordering consistent
+// with ordinary pointer comparison; otherwise they could ignore m_ptr, and just compare m_refs.
+
+template <typename T>
+wp<T> wp<T>::fromExisting(T* other) {
+ if (!other) return nullptr;
+
+ auto refs = other->getWeakRefs();
+ refs->incWeakRequireWeak(other);
+
+ wp<T> ret;
+ ret.m_ptr = other;
+ ret.m_refs = refs;
+ return ret;
+}
+
+#if !defined(ANDROID_UTILS_REF_BASE_DISABLE_IMPLICIT_CONSTRUCTION)
+template<typename T>
+wp<T>::wp(T* other)
+ : m_ptr(other)
+{
+ m_refs = other ? m_refs = other->createWeak(this) : nullptr;
+}
+
+template <typename T>
+template <typename U>
+wp<T>::wp(U* other) : m_ptr(other) {
+ m_refs = other ? other->createWeak(this) : nullptr;
+}
+
+template <typename T>
+wp<T>& wp<T>::operator=(T* other) {
+ weakref_type* newRefs = other ? other->createWeak(this) : nullptr;
+ if (m_ptr) m_refs->decWeak(this);
+ m_ptr = other;
+ m_refs = newRefs;
+ return *this;
+}
+
+template <typename T>
+template <typename U>
+wp<T>& wp<T>::operator=(U* other) {
+ weakref_type* newRefs = other ? other->createWeak(this) : 0;
+ if (m_ptr) m_refs->decWeak(this);
+ m_ptr = other;
+ m_refs = newRefs;
+ return *this;
+}
+#endif
+
+template<typename T>
+wp<T>::wp(const wp<T>& other)
+ : m_ptr(other.m_ptr), m_refs(other.m_refs)
+{
+ if (m_ptr) m_refs->incWeak(this);
+}
+
+template<typename T>
+wp<T>::wp(const sp<T>& other)
+ : m_ptr(other.m_ptr)
+{
+ m_refs = m_ptr ? m_ptr->createWeak(this) : nullptr;
+}
+
+template<typename T> template<typename U>
+wp<T>::wp(const wp<U>& other)
+ : m_ptr(other.m_ptr)
+{
+ if (m_ptr) {
+ m_refs = other.m_refs;
+ m_refs->incWeak(this);
+ } else {
+ m_refs = nullptr;
+ }
+}
+
+template<typename T> template<typename U>
+wp<T>::wp(const sp<U>& other)
+ : m_ptr(other.m_ptr)
+{
+ m_refs = m_ptr ? m_ptr->createWeak(this) : nullptr;
+}
+
+template<typename T>
+wp<T>::~wp()
+{
+ if (m_ptr) m_refs->decWeak(this);
+}
+
+template<typename T>
+wp<T>& wp<T>::operator = (const wp<T>& other)
+{
+ weakref_type* otherRefs(other.m_refs);
+ T* otherPtr(other.m_ptr);
+ if (otherPtr) otherRefs->incWeak(this);
+ if (m_ptr) m_refs->decWeak(this);
+ m_ptr = otherPtr;
+ m_refs = otherRefs;
+ return *this;
+}
+
+template<typename T>
+wp<T>& wp<T>::operator = (const sp<T>& other)
+{
+ weakref_type* newRefs =
+ other != nullptr ? other->createWeak(this) : nullptr;
+ T* otherPtr(other.m_ptr);
+ if (m_ptr) m_refs->decWeak(this);
+ m_ptr = otherPtr;
+ m_refs = newRefs;
+ return *this;
+}
+
+template<typename T> template<typename U>
+wp<T>& wp<T>::operator = (const wp<U>& other)
+{
+ weakref_type* otherRefs(other.m_refs);
+ U* otherPtr(other.m_ptr);
+ if (otherPtr) otherRefs->incWeak(this);
+ if (m_ptr) m_refs->decWeak(this);
+ m_ptr = otherPtr;
+ m_refs = otherRefs;
+ return *this;
+}
+
+template<typename T> template<typename U>
+wp<T>& wp<T>::operator = (const sp<U>& other)
+{
+ weakref_type* newRefs =
+ other != nullptr ? other->createWeak(this) : 0;
+ U* otherPtr(other.m_ptr);
+ if (m_ptr) m_refs->decWeak(this);
+ m_ptr = otherPtr;
+ m_refs = newRefs;
+ return *this;
+}
+
+template<typename T>
+void wp<T>::set_object_and_refs(T* other, weakref_type* refs)
+{
+ if (other) refs->incWeak(this);
+ if (m_ptr) m_refs->decWeak(this);
+ m_ptr = other;
+ m_refs = refs;
+}
+
+template<typename T>
+sp<T> wp<T>::promote() const
+{
+ sp<T> result;
+ if (m_ptr && m_refs->attemptIncStrong(&result)) {
+ result.set_pointer(m_ptr);
+ }
+ return result;
+}
+
+template<typename T>
+void wp<T>::clear()
+{
+ if (m_ptr) {
+ m_refs->decWeak(this);
+ m_refs = 0;
+ m_ptr = 0;
+ }
+}
+
+// ---------------------------------------------------------------------------
+
+// this class just serves as a namespace so TYPE::moveReferences can stay
+// private.
+class ReferenceMover {
+public:
+ // it would be nice if we could make sure no extra code is generated
+ // for sp<TYPE> or wp<TYPE> when TYPE is a descendant of RefBase:
+ // Using a sp<RefBase> override doesn't work; it's a bit like we wanted
+ // a template<typename TYPE inherits RefBase> template...
+
+ template<typename TYPE> static inline
+ void move_references(sp<TYPE>* dest, sp<TYPE> const* src, size_t n) {
+
+ class Renamer : public ReferenceRenamer {
+ sp<TYPE>* d_;
+ sp<TYPE> const* s_;
+ virtual void operator()(size_t i) const {
+ // The id are known to be the sp<>'s this pointer
+ TYPE::renameRefId(d_[i].get(), &s_[i], &d_[i]);
+ }
+ public:
+ Renamer(sp<TYPE>* d, sp<TYPE> const* s) : d_(d), s_(s) { }
+ virtual ~Renamer() { }
+ };
+
+ memmove(dest, src, n*sizeof(sp<TYPE>));
+ TYPE::renameRefs(n, Renamer(dest, src));
+ }
+
+
+ template<typename TYPE> static inline
+ void move_references(wp<TYPE>* dest, wp<TYPE> const* src, size_t n) {
+
+ class Renamer : public ReferenceRenamer {
+ wp<TYPE>* d_;
+ wp<TYPE> const* s_;
+ virtual void operator()(size_t i) const {
+ // The id are known to be the wp<>'s this pointer
+ TYPE::renameRefId(d_[i].get_refs(), &s_[i], &d_[i]);
+ }
+ public:
+ Renamer(wp<TYPE>* rd, wp<TYPE> const* rs) : d_(rd), s_(rs) { }
+ virtual ~Renamer() { }
+ };
+
+ memmove(dest, src, n*sizeof(wp<TYPE>));
+ TYPE::renameRefs(n, Renamer(dest, src));
+ }
+};
+
+// specialization for moving sp<> and wp<> types.
+// these are used by the [Sorted|Keyed]Vector<> implementations
+// sp<> and wp<> need to be handled specially, because they do not
+// have trivial copy operation in the general case (see RefBase.cpp
+// when DEBUG ops are enabled), but can be implemented very
+// efficiently in most cases.
+
+template<typename TYPE> inline
+void move_forward_type(sp<TYPE>* d, sp<TYPE> const* s, size_t n) {
+ ReferenceMover::move_references(d, s, n);
+}
+
+template<typename TYPE> inline
+void move_backward_type(sp<TYPE>* d, sp<TYPE> const* s, size_t n) {
+ ReferenceMover::move_references(d, s, n);
+}
+
+template<typename TYPE> inline
+void move_forward_type(wp<TYPE>* d, wp<TYPE> const* s, size_t n) {
+ ReferenceMover::move_references(d, s, n);
+}
+
+template<typename TYPE> inline
+void move_backward_type(wp<TYPE>* d, wp<TYPE> const* s, size_t n) {
+ ReferenceMover::move_references(d, s, n);
+}
+
+} // namespace android
+
+namespace libutilsinternal {
+template <typename T, typename = void>
+struct is_complete_type : std::false_type {};
+
+template <typename T>
+struct is_complete_type<T, decltype(void(sizeof(T)))> : std::true_type {};
+} // namespace libutilsinternal
+
+namespace std {
+
+// Define `RefBase` specific versions of `std::make_shared` and
+// `std::make_unique` to block people from using them. Using them to allocate
+// `RefBase` objects results in double ownership. Use
+// `sp<T>::make(...)` instead.
+//
+// Note: We exclude incomplete types because `std::is_base_of` is undefined in
+// that case.
+
+template <typename T, typename... Args,
+ typename std::enable_if<libutilsinternal::is_complete_type<T>::value, bool>::value = true,
+ typename std::enable_if<std::is_base_of<android::RefBase, T>::value, bool>::value = true>
+shared_ptr<T> make_shared(Args...) { // SEE COMMENT ABOVE.
+ static_assert(!std::is_base_of<android::RefBase, T>::value, "Must use RefBase with sp<>");
+}
+
+template <typename T, typename... Args,
+ typename std::enable_if<libutilsinternal::is_complete_type<T>::value, bool>::value = true,
+ typename std::enable_if<std::is_base_of<android::RefBase, T>::value, bool>::value = true>
+unique_ptr<T> make_unique(Args...) { // SEE COMMENT ABOVE.
+ static_assert(!std::is_base_of<android::RefBase, T>::value, "Must use RefBase with sp<>");
+}
+
+} // namespace std
+
+// ---------------------------------------------------------------------------
+
+#endif // ANDROID_REF_BASE_H
diff --git a/libutils/binder/include/utils/String16.h b/libutils/binder/include/utils/String16.h
new file mode 100644
index 0000000..c713576
--- /dev/null
+++ b/libutils/binder/include/utils/String16.h
@@ -0,0 +1,383 @@
+/*
+ * Copyright (C) 2005 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.
+ */
+
+#ifndef ANDROID_STRING16_H
+#define ANDROID_STRING16_H
+
+#include <iostream>
+#include <string>
+
+#include <utils/Errors.h>
+#include <utils/String8.h>
+#include <utils/TypeHelpers.h>
+
+#if __has_include(<string_view>)
+#include <string_view>
+#define HAS_STRING_VIEW
+#endif
+
+// ---------------------------------------------------------------------------
+
+namespace android {
+
+// ---------------------------------------------------------------------------
+
+template <size_t N>
+class StaticString16;
+
+// DO NOT USE: please use std::u16string
+
+//! This is a string holding UTF-16 characters.
+class String16
+{
+public:
+ String16();
+ String16(const String16& o);
+ String16(String16&& o) noexcept;
+ String16(const String16& o,
+ size_t len,
+ size_t begin=0);
+ explicit String16(const char16_t* o);
+ explicit String16(const char16_t* o, size_t len);
+ explicit String16(const String8& o);
+ explicit String16(const char* o);
+ explicit String16(const char* o, size_t len);
+
+ ~String16();
+
+ inline const char16_t* c_str() const;
+
+ size_t size() const;
+ inline bool empty() const;
+
+ inline size_t length() const;
+
+ void setTo(const String16& other);
+ status_t setTo(const char16_t* other);
+ status_t setTo(const char16_t* other, size_t len);
+ status_t setTo(const String16& other,
+ size_t len,
+ size_t begin=0);
+
+ status_t append(const String16& other);
+ status_t append(const char16_t* other, size_t len);
+
+ inline String16& operator=(const String16& other);
+ String16& operator=(String16&& other) noexcept;
+
+ inline String16& operator+=(const String16& other);
+ inline String16 operator+(const String16& other) const;
+
+ status_t insert(size_t pos, const char16_t* chrs);
+ status_t insert(size_t pos,
+ const char16_t* chrs, size_t len);
+
+ ssize_t findFirst(char16_t c) const;
+ ssize_t findLast(char16_t c) const;
+
+ bool startsWith(const String16& prefix) const;
+ bool startsWith(const char16_t* prefix) const;
+
+ bool contains(const char16_t* chrs) const;
+ inline bool contains(const String16& other) const;
+
+ status_t replaceAll(char16_t replaceThis,
+ char16_t withThis);
+
+ inline int compare(const String16& other) const;
+
+ inline bool operator<(const String16& other) const;
+ inline bool operator<=(const String16& other) const;
+ inline bool operator==(const String16& other) const;
+ inline bool operator!=(const String16& other) const;
+ inline bool operator>=(const String16& other) const;
+ inline bool operator>(const String16& other) const;
+
+ inline bool operator<(const char16_t* other) const;
+ inline bool operator<=(const char16_t* other) const;
+ inline bool operator==(const char16_t* other) const;
+ inline bool operator!=(const char16_t* other) const;
+ inline bool operator>=(const char16_t* other) const;
+ inline bool operator>(const char16_t* other) const;
+
+ inline operator const char16_t*() const;
+
+#ifdef HAS_STRING_VIEW
+ // Implicit cast to std::u16string is not implemented on purpose - u16string_view is much
+ // lighter and if one needs, they can still create u16string from u16string_view.
+ inline operator std::u16string_view() const;
+#endif
+
+ // Static and non-static String16 behave the same for the users, so
+ // this method isn't of much use for the users. It is public for testing.
+ bool isStaticString() const;
+
+ private:
+ /*
+ * A flag indicating the type of underlying buffer.
+ */
+ static constexpr uint32_t kIsSharedBufferAllocated = 0x80000000;
+
+ /*
+ * alloc() returns void* so that SharedBuffer class is not exposed.
+ */
+ static void* alloc(size_t size);
+ static char16_t* allocFromUTF8(const char* u8str, size_t u8len);
+ static char16_t* allocFromUTF16(const char16_t* u16str, size_t u16len);
+
+ /*
+ * edit() and editResize() return void* so that SharedBuffer class
+ * is not exposed.
+ */
+ void* edit();
+ void* editResize(size_t new_size);
+
+ void acquire();
+ void release();
+
+ size_t staticStringSize() const;
+
+ const char16_t* mString;
+
+protected:
+ /*
+ * Data structure used to allocate static storage for static String16.
+ *
+ * Note that this data structure and SharedBuffer are used interchangably
+ * as the underlying data structure for a String16. Therefore, the layout
+ * of this data structure must match the part in SharedBuffer that is
+ * visible to String16.
+ */
+ template <size_t N>
+ struct StaticData {
+ // The high bit of 'size' is used as a flag.
+ static_assert(N - 1 < kIsSharedBufferAllocated, "StaticString16 too long!");
+ constexpr StaticData() : size(N - 1), data{0} {}
+ const uint32_t size;
+ char16_t data[N];
+
+ constexpr StaticData(const StaticData<N>&) = default;
+ };
+
+ /*
+ * Helper function for constructing a StaticData object.
+ */
+ template <size_t N>
+ static constexpr const StaticData<N> makeStaticData(const char16_t (&s)[N]) {
+ StaticData<N> r;
+ // The 'size' field is at the same location where mClientMetadata would
+ // be for a SharedBuffer. We do NOT set kIsSharedBufferAllocated flag
+ // here.
+ for (size_t i = 0; i < N - 1; ++i) r.data[i] = s[i];
+ return r;
+ }
+
+ template <size_t N>
+ explicit constexpr String16(const StaticData<N>& s) : mString(s.data) {}
+
+// These symbols are for potential backward compatibility with prebuilts. To be removed.
+#ifdef ENABLE_STRING16_OBSOLETE_METHODS
+public:
+#else
+private:
+#endif
+ inline const char16_t* string() const;
+};
+
+// String16 can be trivially moved using memcpy() because moving does not
+// require any change to the underlying SharedBuffer contents or reference count.
+ANDROID_TRIVIAL_MOVE_TRAIT(String16)
+
+static inline std::ostream& operator<<(std::ostream& os, const String16& str) {
+ os << String8(str);
+ return os;
+}
+
+// ---------------------------------------------------------------------------
+
+/*
+ * A StaticString16 object is a specialized String16 object. Instead of holding
+ * the string data in a ref counted SharedBuffer object, it holds data in a
+ * buffer within StaticString16 itself. Note that this buffer is NOT ref
+ * counted and is assumed to be available for as long as there is at least a
+ * String16 object using it. Therefore, one must be extra careful to NEVER
+ * assign a StaticString16 to a String16 that outlives the StaticString16
+ * object.
+ *
+ * THE SAFEST APPROACH IS TO USE StaticString16 ONLY AS GLOBAL VARIABLES.
+ *
+ * A StaticString16 SHOULD NEVER APPEAR IN APIs. USE String16 INSTEAD.
+ */
+template <size_t N>
+class StaticString16 : public String16 {
+public:
+ constexpr StaticString16(const char16_t (&s)[N]) : String16(mData), mData(makeStaticData(s)) {}
+
+ constexpr StaticString16(const StaticString16<N>& other)
+ : String16(mData), mData(other.mData) {}
+
+ constexpr StaticString16(const StaticString16<N>&&) = delete;
+
+ // There is no reason why one would want to 'new' a StaticString16. Delete
+ // it to discourage misuse.
+ static void* operator new(std::size_t) = delete;
+
+private:
+ const StaticData<N> mData;
+};
+
+template <typename F>
+StaticString16(const F&)->StaticString16<sizeof(F) / sizeof(char16_t)>;
+
+// ---------------------------------------------------------------------------
+// No user servicable parts below.
+
+inline int compare_type(const String16& lhs, const String16& rhs)
+{
+ return lhs.compare(rhs);
+}
+
+inline int strictly_order_type(const String16& lhs, const String16& rhs)
+{
+ return compare_type(lhs, rhs) < 0;
+}
+
+inline const char16_t* String16::c_str() const
+{
+ return mString;
+}
+
+inline const char16_t* String16::string() const
+{
+ return mString;
+}
+
+inline bool String16::empty() const
+{
+ return length() == 0;
+}
+
+inline size_t String16::length() const
+{
+ return size();
+}
+
+inline bool String16::contains(const String16& other) const
+{
+ return contains(other.c_str());
+}
+
+inline String16& String16::operator=(const String16& other)
+{
+ setTo(other);
+ return *this;
+}
+
+inline String16& String16::operator+=(const String16& other)
+{
+ append(other);
+ return *this;
+}
+
+inline String16 String16::operator+(const String16& other) const
+{
+ String16 tmp(*this);
+ tmp += other;
+ return tmp;
+}
+
+inline int String16::compare(const String16& other) const
+{
+ return strzcmp16(mString, size(), other.mString, other.size());
+}
+
+inline bool String16::operator<(const String16& other) const
+{
+ return strzcmp16(mString, size(), other.mString, other.size()) < 0;
+}
+
+inline bool String16::operator<=(const String16& other) const
+{
+ return strzcmp16(mString, size(), other.mString, other.size()) <= 0;
+}
+
+inline bool String16::operator==(const String16& other) const
+{
+ return strzcmp16(mString, size(), other.mString, other.size()) == 0;
+}
+
+inline bool String16::operator!=(const String16& other) const
+{
+ return strzcmp16(mString, size(), other.mString, other.size()) != 0;
+}
+
+inline bool String16::operator>=(const String16& other) const
+{
+ return strzcmp16(mString, size(), other.mString, other.size()) >= 0;
+}
+
+inline bool String16::operator>(const String16& other) const
+{
+ return strzcmp16(mString, size(), other.mString, other.size()) > 0;
+}
+
+inline bool String16::operator<(const char16_t* other) const
+{
+ return strcmp16(mString, other) < 0;
+}
+
+inline bool String16::operator<=(const char16_t* other) const
+{
+ return strcmp16(mString, other) <= 0;
+}
+
+inline bool String16::operator==(const char16_t* other) const
+{
+ return strcmp16(mString, other) == 0;
+}
+
+inline bool String16::operator!=(const char16_t* other) const
+{
+ return strcmp16(mString, other) != 0;
+}
+
+inline bool String16::operator>=(const char16_t* other) const
+{
+ return strcmp16(mString, other) >= 0;
+}
+
+inline bool String16::operator>(const char16_t* other) const
+{
+ return strcmp16(mString, other) > 0;
+}
+
+inline String16::operator const char16_t*() const
+{
+ return mString;
+}
+
+inline String16::operator std::u16string_view() const
+{
+ return {mString, length()};
+}
+
+} // namespace android
+
+// ---------------------------------------------------------------------------
+
+#undef HAS_STRING_VIEW
+
+#endif // ANDROID_STRING16_H
diff --git a/libutils/binder/include/utils/String8.h b/libutils/binder/include/utils/String8.h
new file mode 100644
index 0000000..6d25072
--- /dev/null
+++ b/libutils/binder/include/utils/String8.h
@@ -0,0 +1,354 @@
+/*
+ * Copyright (C) 2005 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.
+ */
+
+#ifndef ANDROID_STRING8_H
+#define ANDROID_STRING8_H
+
+#include <iostream>
+
+#include <utils/Errors.h>
+#include <utils/Unicode.h>
+#include <utils/TypeHelpers.h>
+
+#include <string.h> // for strcmp
+#include <stdarg.h>
+
+#if __has_include(<string>)
+#include <string>
+#define HAS_STRING
+#endif
+
+#if __has_include(<string_view>)
+#include <string_view>
+#define HAS_STRING_VIEW
+#endif
+
+// ---------------------------------------------------------------------------
+
+namespace android {
+
+class String16;
+
+// DO NOT USE: please use std::string
+
+//! This is a string holding UTF-8 characters. Does not allow the value more
+// than 0x10FFFF, which is not valid unicode codepoint.
+class String8
+{
+public:
+ String8();
+ String8(const String8& o);
+ explicit String8(const char* o);
+ explicit String8(const char* o, size_t numChars);
+
+ explicit String8(const String16& o);
+ explicit String8(const char16_t* o);
+ explicit String8(const char16_t* o, size_t numChars);
+ explicit String8(const char32_t* o);
+ explicit String8(const char32_t* o, size_t numChars);
+ ~String8();
+
+ static String8 format(const char* fmt, ...) __attribute__((format (printf, 1, 2)));
+ static String8 formatV(const char* fmt, va_list args);
+
+ inline const char* c_str() const;
+
+ inline size_t size() const;
+ inline size_t bytes() const;
+ inline bool empty() const;
+
+ size_t length() const;
+
+ void clear();
+
+ void setTo(const String8& other);
+ status_t setTo(const char* other);
+ status_t setTo(const char* other, size_t numChars);
+ status_t setTo(const char16_t* other, size_t numChars);
+ status_t setTo(const char32_t* other,
+ size_t length);
+
+ status_t append(const String8& other);
+ status_t append(const char* other);
+ status_t append(const char* other, size_t numChars);
+
+ status_t appendFormat(const char* fmt, ...)
+ __attribute__((format (printf, 2, 3)));
+ status_t appendFormatV(const char* fmt, va_list args);
+
+ inline String8& operator=(const String8& other);
+ inline String8& operator=(const char* other);
+
+ inline String8& operator+=(const String8& other);
+ inline String8 operator+(const String8& other) const;
+
+ inline String8& operator+=(const char* other);
+ inline String8 operator+(const char* other) const;
+
+ inline int compare(const String8& other) const;
+
+ inline bool operator<(const String8& other) const;
+ inline bool operator<=(const String8& other) const;
+ inline bool operator==(const String8& other) const;
+ inline bool operator!=(const String8& other) const;
+ inline bool operator>=(const String8& other) const;
+ inline bool operator>(const String8& other) const;
+
+ inline bool operator<(const char* other) const;
+ inline bool operator<=(const char* other) const;
+ inline bool operator==(const char* other) const;
+ inline bool operator!=(const char* other) const;
+ inline bool operator>=(const char* other) const;
+ inline bool operator>(const char* other) const;
+
+ inline operator const char*() const;
+
+#ifdef HAS_STRING_VIEW
+ inline explicit operator std::string_view() const;
+#endif
+
+ char* lockBuffer(size_t size);
+ void unlockBuffer();
+ status_t unlockBuffer(size_t size);
+
+ // return the index of the first byte of other in this at or after
+ // start, or -1 if not found
+ ssize_t find(const char* other, size_t start = 0) const;
+ inline ssize_t find(const String8& other, size_t start = 0) const;
+
+ // return true if this string contains the specified substring
+ inline bool contains(const char* other) const;
+ inline bool contains(const String8& other) const;
+
+ // removes all occurrence of the specified substring
+ // returns true if any were found and removed
+ bool removeAll(const char* other);
+ inline bool removeAll(const String8& other);
+
+ void toLower();
+
+private:
+ String8 getPathDir(void) const;
+ String8 getPathExtension(void) const;
+
+ status_t real_append(const char* other, size_t numChars);
+
+ const char* mString;
+
+// These symbols are for potential backward compatibility with prebuilts. To be removed.
+#ifdef ENABLE_STRING8_OBSOLETE_METHODS
+public:
+#else
+private:
+#endif
+ inline const char* string() const;
+ inline bool isEmpty() const;
+};
+
+// String8 can be trivially moved using memcpy() because moving does not
+// require any change to the underlying SharedBuffer contents or reference count.
+ANDROID_TRIVIAL_MOVE_TRAIT(String8)
+
+static inline std::ostream& operator<<(std::ostream& os, const String8& str) {
+ os << str.c_str();
+ return os;
+}
+
+// ---------------------------------------------------------------------------
+// No user servicable parts below.
+
+inline int compare_type(const String8& lhs, const String8& rhs)
+{
+ return lhs.compare(rhs);
+}
+
+inline int strictly_order_type(const String8& lhs, const String8& rhs)
+{
+ return compare_type(lhs, rhs) < 0;
+}
+
+inline const char* String8::c_str() const
+{
+ return mString;
+}
+inline const char* String8::string() const
+{
+ return mString;
+}
+
+inline size_t String8::size() const
+{
+ return length();
+}
+
+inline bool String8::empty() const
+{
+ return length() == 0;
+}
+
+inline bool String8::isEmpty() const
+{
+ return length() == 0;
+}
+
+inline size_t String8::bytes() const
+{
+ return length();
+}
+
+inline ssize_t String8::find(const String8& other, size_t start) const
+{
+ return find(other.c_str(), start);
+}
+
+inline bool String8::contains(const char* other) const
+{
+ return find(other) >= 0;
+}
+
+inline bool String8::contains(const String8& other) const
+{
+ return contains(other.c_str());
+}
+
+inline bool String8::removeAll(const String8& other)
+{
+ return removeAll(other.c_str());
+}
+
+inline String8& String8::operator=(const String8& other)
+{
+ setTo(other);
+ return *this;
+}
+
+inline String8& String8::operator=(const char* other)
+{
+ setTo(other);
+ return *this;
+}
+
+inline String8& String8::operator+=(const String8& other)
+{
+ append(other);
+ return *this;
+}
+
+inline String8 String8::operator+(const String8& other) const
+{
+ String8 tmp(*this);
+ tmp += other;
+ return tmp;
+}
+
+inline String8& String8::operator+=(const char* other)
+{
+ append(other);
+ return *this;
+}
+
+inline String8 String8::operator+(const char* other) const
+{
+ String8 tmp(*this);
+ tmp += other;
+ return tmp;
+}
+
+inline int String8::compare(const String8& other) const
+{
+ return strcmp(mString, other.mString);
+}
+
+inline bool String8::operator<(const String8& other) const
+{
+ return strcmp(mString, other.mString) < 0;
+}
+
+inline bool String8::operator<=(const String8& other) const
+{
+ return strcmp(mString, other.mString) <= 0;
+}
+
+inline bool String8::operator==(const String8& other) const
+{
+ return strcmp(mString, other.mString) == 0;
+}
+
+inline bool String8::operator!=(const String8& other) const
+{
+ return strcmp(mString, other.mString) != 0;
+}
+
+inline bool String8::operator>=(const String8& other) const
+{
+ return strcmp(mString, other.mString) >= 0;
+}
+
+inline bool String8::operator>(const String8& other) const
+{
+ return strcmp(mString, other.mString) > 0;
+}
+
+inline bool String8::operator<(const char* other) const
+{
+ return strcmp(mString, other) < 0;
+}
+
+inline bool String8::operator<=(const char* other) const
+{
+ return strcmp(mString, other) <= 0;
+}
+
+inline bool String8::operator==(const char* other) const
+{
+ return strcmp(mString, other) == 0;
+}
+
+inline bool String8::operator!=(const char* other) const
+{
+ return strcmp(mString, other) != 0;
+}
+
+inline bool String8::operator>=(const char* other) const
+{
+ return strcmp(mString, other) >= 0;
+}
+
+inline bool String8::operator>(const char* other) const
+{
+ return strcmp(mString, other) > 0;
+}
+
+inline String8::operator const char*() const
+{
+ return mString;
+}
+
+#ifdef HAS_STRING_VIEW
+inline String8::operator std::string_view() const
+{
+ return {mString, length()};
+}
+#endif
+
+} // namespace android
+
+// ---------------------------------------------------------------------------
+
+#undef HAS_STRING
+#undef HAS_STRING_VIEW
+
+#endif // ANDROID_STRING8_H
diff --git a/libutils/binder/include/utils/StrongPointer.h b/libutils/binder/include/utils/StrongPointer.h
new file mode 100644
index 0000000..54aa691
--- /dev/null
+++ b/libutils/binder/include/utils/StrongPointer.h
@@ -0,0 +1,361 @@
+/*
+ * Copyright (C) 2005 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.
+ */
+
+#ifndef ANDROID_STRONG_POINTER_H
+#define ANDROID_STRONG_POINTER_H
+
+#include <functional>
+#include <type_traits> // for common_type.
+
+// ---------------------------------------------------------------------------
+namespace android {
+
+template<typename T> class wp;
+
+// ---------------------------------------------------------------------------
+
+template<typename T>
+class sp {
+public:
+ inline sp() : m_ptr(nullptr) { }
+
+ // The old way of using sp<> was like this. This is bad because it relies
+ // on implicit conversion to sp<>, which we would like to remove (if an
+ // object is being managed some other way, this is double-ownership). We
+ // want to move away from this:
+ //
+ // sp<Foo> foo = new Foo(...); // DO NOT DO THIS
+ //
+ // Instead, prefer to do this:
+ //
+ // sp<Foo> foo = sp<Foo>::make(...); // DO THIS
+ //
+ // Sometimes, in order to use this, when a constructor is marked as private,
+ // you may need to add this to your class:
+ //
+ // friend class sp<Foo>;
+ template <typename... Args>
+ static inline sp<T> make(Args&&... args);
+
+ // if nullptr, returns nullptr
+ //
+ // if a strong pointer is already available, this will retrieve it,
+ // otherwise, this will abort
+ static inline sp<T> fromExisting(T* other);
+
+ // for more information about this macro and correct RefBase usage, see
+ // the comment at the top of utils/RefBase.h
+#if defined(ANDROID_UTILS_REF_BASE_DISABLE_IMPLICIT_CONSTRUCTION)
+ sp(std::nullptr_t) : sp() {}
+#else
+ sp(T* other); // NOLINT(implicit)
+ template <typename U>
+ sp(U* other); // NOLINT(implicit)
+ sp& operator=(T* other);
+ template <typename U>
+ sp& operator=(U* other);
+#endif
+
+ sp(const sp<T>& other);
+ sp(sp<T>&& other) noexcept;
+
+ template<typename U> sp(const sp<U>& other); // NOLINT(implicit)
+ template<typename U> sp(sp<U>&& other); // NOLINT(implicit)
+
+ // Cast a strong pointer directly from one type to another. Constructors
+ // allow changing types, but only if they are pointer-compatible. This does
+ // a static_cast internally.
+ template <typename U>
+ static inline sp<T> cast(const sp<U>& other);
+
+ ~sp();
+
+ // Assignment
+
+ sp& operator = (const sp<T>& other);
+ sp& operator=(sp<T>&& other) noexcept;
+
+ template<typename U> sp& operator = (const sp<U>& other);
+ template<typename U> sp& operator = (sp<U>&& other);
+
+ //! Special optimization for use by ProcessState (and nobody else).
+ void force_set(T* other);
+
+ // Reset
+
+ void clear();
+
+ // Accessors
+
+ inline T& operator* () const { return *m_ptr; }
+ inline T* operator-> () const { return m_ptr; }
+ inline T* get() const { return m_ptr; }
+ inline explicit operator bool () const { return m_ptr != nullptr; }
+
+ // Punt these to the wp<> implementation.
+ template<typename U>
+ inline bool operator == (const wp<U>& o) const {
+ return o == *this;
+ }
+
+ template<typename U>
+ inline bool operator != (const wp<U>& o) const {
+ return o != *this;
+ }
+
+private:
+ template<typename Y> friend class sp;
+ template<typename Y> friend class wp;
+ void set_pointer(T* ptr);
+ T* m_ptr;
+};
+
+#define COMPARE_STRONG(_op_) \
+ template <typename T, typename U> \
+ static inline bool operator _op_(const sp<T>& t, const sp<U>& u) { \
+ return t.get() _op_ u.get(); \
+ } \
+ template <typename T, typename U> \
+ static inline bool operator _op_(const T* t, const sp<U>& u) { \
+ return t _op_ u.get(); \
+ } \
+ template <typename T, typename U> \
+ static inline bool operator _op_(const sp<T>& t, const U* u) { \
+ return t.get() _op_ u; \
+ } \
+ template <typename T> \
+ static inline bool operator _op_(const sp<T>& t, std::nullptr_t) { \
+ return t.get() _op_ nullptr; \
+ } \
+ template <typename T> \
+ static inline bool operator _op_(std::nullptr_t, const sp<T>& t) { \
+ return nullptr _op_ t.get(); \
+ }
+
+template <template <typename C> class comparator, typename T, typename U>
+static inline bool _sp_compare_(T* a, U* b) {
+ return comparator<typename std::common_type<T*, U*>::type>()(a, b);
+}
+
+#define COMPARE_STRONG_FUNCTIONAL(_op_, _compare_) \
+ template <typename T, typename U> \
+ static inline bool operator _op_(const sp<T>& t, const sp<U>& u) { \
+ return _sp_compare_<_compare_>(t.get(), u.get()); \
+ } \
+ template <typename T, typename U> \
+ static inline bool operator _op_(const T* t, const sp<U>& u) { \
+ return _sp_compare_<_compare_>(t, u.get()); \
+ } \
+ template <typename T, typename U> \
+ static inline bool operator _op_(const sp<T>& t, const U* u) { \
+ return _sp_compare_<_compare_>(t.get(), u); \
+ } \
+ template <typename T> \
+ static inline bool operator _op_(const sp<T>& t, std::nullptr_t) { \
+ return _sp_compare_<_compare_>(t.get(), nullptr); \
+ } \
+ template <typename T> \
+ static inline bool operator _op_(std::nullptr_t, const sp<T>& t) { \
+ return _sp_compare_<_compare_>(nullptr, t.get()); \
+ }
+
+COMPARE_STRONG(==)
+COMPARE_STRONG(!=)
+COMPARE_STRONG_FUNCTIONAL(>, std::greater)
+COMPARE_STRONG_FUNCTIONAL(<, std::less)
+COMPARE_STRONG_FUNCTIONAL(<=, std::less_equal)
+COMPARE_STRONG_FUNCTIONAL(>=, std::greater_equal)
+
+#undef COMPARE_STRONG
+#undef COMPARE_STRONG_FUNCTIONAL
+
+// For code size reasons, we do not want these inlined or templated.
+void sp_report_race();
+
+// ---------------------------------------------------------------------------
+// No user serviceable parts below here.
+
+// TODO: Ideally we should find a way to increment the reference count before running the
+// constructor, so that generating an sp<> to this in the constructor is no longer dangerous.
+template <typename T>
+template <typename... Args>
+sp<T> sp<T>::make(Args&&... args) {
+ T* t = new T(std::forward<Args>(args)...);
+ sp<T> result;
+ result.m_ptr = t;
+ t->incStrong(t);
+ return result;
+}
+
+template <typename T>
+sp<T> sp<T>::fromExisting(T* other) {
+ if (other) {
+ other->incStrongRequireStrong(other);
+ sp<T> result;
+ result.m_ptr = other;
+ return result;
+ }
+ return nullptr;
+}
+
+#if !defined(ANDROID_UTILS_REF_BASE_DISABLE_IMPLICIT_CONSTRUCTION)
+template<typename T>
+sp<T>::sp(T* other)
+ : m_ptr(other) {
+ if (other) {
+ other->incStrong(this);
+ }
+}
+
+template <typename T>
+template <typename U>
+sp<T>::sp(U* other) : m_ptr(other) {
+ if (other) {
+ (static_cast<T*>(other))->incStrong(this);
+ }
+}
+
+template <typename T>
+sp<T>& sp<T>::operator=(T* other) {
+ T* oldPtr(*const_cast<T* volatile*>(&m_ptr));
+ if (other) {
+ other->incStrong(this);
+ }
+ if (oldPtr) oldPtr->decStrong(this);
+ if (oldPtr != *const_cast<T* volatile*>(&m_ptr)) sp_report_race();
+ m_ptr = other;
+ return *this;
+}
+#endif
+
+template<typename T>
+sp<T>::sp(const sp<T>& other)
+ : m_ptr(other.m_ptr) {
+ if (m_ptr)
+ m_ptr->incStrong(this);
+}
+
+template <typename T>
+sp<T>::sp(sp<T>&& other) noexcept : m_ptr(other.m_ptr) {
+ other.m_ptr = nullptr;
+}
+
+template<typename T> template<typename U>
+sp<T>::sp(const sp<U>& other)
+ : m_ptr(other.m_ptr) {
+ if (m_ptr)
+ m_ptr->incStrong(this);
+}
+
+template<typename T> template<typename U>
+sp<T>::sp(sp<U>&& other)
+ : m_ptr(other.m_ptr) {
+ other.m_ptr = nullptr;
+}
+
+template <typename T>
+template <typename U>
+sp<T> sp<T>::cast(const sp<U>& other) {
+ return sp<T>::fromExisting(static_cast<T*>(other.get()));
+}
+
+template<typename T>
+sp<T>::~sp() {
+ if (m_ptr)
+ m_ptr->decStrong(this);
+}
+
+template<typename T>
+sp<T>& sp<T>::operator =(const sp<T>& other) {
+ // Force m_ptr to be read twice, to heuristically check for data races.
+ T* oldPtr(*const_cast<T* volatile*>(&m_ptr));
+ T* otherPtr(other.m_ptr);
+ if (otherPtr) otherPtr->incStrong(this);
+ if (oldPtr) oldPtr->decStrong(this);
+ if (oldPtr != *const_cast<T* volatile*>(&m_ptr)) sp_report_race();
+ m_ptr = otherPtr;
+ return *this;
+}
+
+template <typename T>
+sp<T>& sp<T>::operator=(sp<T>&& other) noexcept {
+ T* oldPtr(*const_cast<T* volatile*>(&m_ptr));
+ if (oldPtr) oldPtr->decStrong(this);
+ if (oldPtr != *const_cast<T* volatile*>(&m_ptr)) sp_report_race();
+ m_ptr = other.m_ptr;
+ other.m_ptr = nullptr;
+ return *this;
+}
+
+template<typename T> template<typename U>
+sp<T>& sp<T>::operator =(const sp<U>& other) {
+ T* oldPtr(*const_cast<T* volatile*>(&m_ptr));
+ T* otherPtr(other.m_ptr);
+ if (otherPtr) otherPtr->incStrong(this);
+ if (oldPtr) oldPtr->decStrong(this);
+ if (oldPtr != *const_cast<T* volatile*>(&m_ptr)) sp_report_race();
+ m_ptr = otherPtr;
+ return *this;
+}
+
+template<typename T> template<typename U>
+sp<T>& sp<T>::operator =(sp<U>&& other) {
+ T* oldPtr(*const_cast<T* volatile*>(&m_ptr));
+ if (m_ptr) m_ptr->decStrong(this);
+ if (oldPtr != *const_cast<T* volatile*>(&m_ptr)) sp_report_race();
+ m_ptr = other.m_ptr;
+ other.m_ptr = nullptr;
+ return *this;
+}
+
+#if !defined(ANDROID_UTILS_REF_BASE_DISABLE_IMPLICIT_CONSTRUCTION)
+template<typename T> template<typename U>
+sp<T>& sp<T>::operator =(U* other) {
+ T* oldPtr(*const_cast<T* volatile*>(&m_ptr));
+ if (other) (static_cast<T*>(other))->incStrong(this);
+ if (oldPtr) oldPtr->decStrong(this);
+ if (oldPtr != *const_cast<T* volatile*>(&m_ptr)) sp_report_race();
+ m_ptr = other;
+ return *this;
+}
+#endif
+
+template<typename T>
+void sp<T>::force_set(T* other) {
+ other->forceIncStrong(this);
+ m_ptr = other;
+}
+
+template<typename T>
+void sp<T>::clear() {
+ T* oldPtr(*const_cast<T* volatile*>(&m_ptr));
+ if (oldPtr) {
+ oldPtr->decStrong(this);
+ if (oldPtr != *const_cast<T* volatile*>(&m_ptr)) sp_report_race();
+ m_ptr = nullptr;
+ }
+}
+
+template<typename T>
+void sp<T>::set_pointer(T* ptr) {
+ m_ptr = ptr;
+}
+
+} // namespace android
+
+// ---------------------------------------------------------------------------
+
+#endif // ANDROID_STRONG_POINTER_H
diff --git a/libutils/binder/include/utils/Unicode.h b/libutils/binder/include/utils/Unicode.h
new file mode 100644
index 0000000..d60d5d6
--- /dev/null
+++ b/libutils/binder/include/utils/Unicode.h
@@ -0,0 +1,139 @@
+/*
+ * Copyright (C) 2005 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.
+ */
+
+#ifndef ANDROID_UNICODE_H
+#define ANDROID_UNICODE_H
+
+#include <sys/types.h>
+#include <stdint.h>
+
+extern "C" {
+
+// Standard string functions on char16_t strings.
+int strcmp16(const char16_t *, const char16_t *);
+int strncmp16(const char16_t *s1, const char16_t *s2, size_t n);
+size_t strlen16(const char16_t *);
+size_t strnlen16(const char16_t *, size_t);
+char16_t *strstr16(const char16_t*, const char16_t*);
+
+// Version of comparison that supports embedded NULs.
+// This is different than strncmp() because we don't stop
+// at a nul character and consider the strings to be different
+// if the lengths are different (thus we need to supply the
+// lengths of both strings). This can also be used when
+// your string is not nul-terminated as it will have the
+// equivalent result as strcmp16 (unlike strncmp16).
+int strzcmp16(const char16_t *s1, size_t n1, const char16_t *s2, size_t n2);
+
+/**
+ * Measure the length of a UTF-32 string in UTF-8. If the string is invalid
+ * such as containing a surrogate character, -1 will be returned.
+ */
+ssize_t utf32_to_utf8_length(const char32_t *src, size_t src_len);
+
+/**
+ * Stores a UTF-8 string converted from "src" in "dst", if "dst_length" is not
+ * large enough to store the string, the part of the "src" string is stored
+ * into "dst" as much as possible. See the examples for more detail.
+ * Returns the size actually used for storing the string.
+ * dst" is not nul-terminated when dst_len is fully used (like strncpy).
+ *
+ * \code
+ * Example 1
+ * "src" == \u3042\u3044 (\xE3\x81\x82\xE3\x81\x84)
+ * "src_len" == 2
+ * "dst_len" >= 7
+ * ->
+ * Returned value == 6
+ * "dst" becomes \xE3\x81\x82\xE3\x81\x84\0
+ * (note that "dst" is nul-terminated)
+ *
+ * Example 2
+ * "src" == \u3042\u3044 (\xE3\x81\x82\xE3\x81\x84)
+ * "src_len" == 2
+ * "dst_len" == 5
+ * ->
+ * Returned value == 3
+ * "dst" becomes \xE3\x81\x82\0
+ * (note that "dst" is nul-terminated, but \u3044 is not stored in "dst"
+ * since "dst" does not have enough size to store the character)
+ *
+ * Example 3
+ * "src" == \u3042\u3044 (\xE3\x81\x82\xE3\x81\x84)
+ * "src_len" == 2
+ * "dst_len" == 6
+ * ->
+ * Returned value == 6
+ * "dst" becomes \xE3\x81\x82\xE3\x81\x84
+ * (note that "dst" is NOT nul-terminated, like strncpy)
+ * \endcode
+ */
+void utf32_to_utf8(const char32_t* src, size_t src_len, char* dst, size_t dst_len);
+
+/**
+ * Returns the unicode value at "index".
+ * Returns -1 when the index is invalid (equals to or more than "src_len").
+ * If returned value is positive, it is able to be converted to char32_t, which
+ * is unsigned. Then, if "next_index" is not NULL, the next index to be used is
+ * stored in "next_index". "next_index" can be NULL.
+ */
+int32_t utf32_from_utf8_at(const char *src, size_t src_len, size_t index, size_t *next_index);
+
+
+/**
+ * Returns the UTF-8 length of UTF-16 string "src".
+ */
+ssize_t utf16_to_utf8_length(const char16_t *src, size_t src_len);
+
+/**
+ * Converts a UTF-16 string to UTF-8. The destination buffer must be large
+ * enough to fit the UTF-16 as measured by utf16_to_utf8_length with an added
+ * NUL terminator.
+ */
+void utf16_to_utf8(const char16_t* src, size_t src_len, char* dst, size_t dst_len);
+
+/**
+ * Returns the UTF-16 length of UTF-8 string "src". Returns -1 in case
+ * it's invalid utf8. No buffer over-read occurs because of bound checks. Using overreadIsFatal you
+ * can ask to log a message and fail in case the invalid utf8 could have caused an override if no
+ * bound checks were used (otherwise -1 is returned).
+ */
+ssize_t utf8_to_utf16_length(const uint8_t* src, size_t srcLen, bool overreadIsFatal = false);
+
+/**
+ * Convert UTF-8 to UTF-16 including surrogate pairs.
+ * Returns a pointer to the end of the string (where a NUL terminator might go
+ * if you wanted to add one). At most dstLen characters are written; it won't emit half a surrogate
+ * pair. If dstLen == 0 nothing is written and dst is returned. If dstLen > SSIZE_MAX it aborts
+ * (this being probably a negative number returned as an error and casted to unsigned).
+ */
+char16_t* utf8_to_utf16_no_null_terminator(
+ const uint8_t* src, size_t srcLen, char16_t* dst, size_t dstLen);
+
+/**
+ * Convert UTF-8 to UTF-16 including surrogate pairs. At most dstLen - 1
+ * characters are written; it won't emit half a surrogate pair; and a NUL terminator is appended
+ * after. dstLen - 1 can be measured beforehand using utf8_to_utf16_length. Aborts if dstLen == 0
+ * (at least one character is needed for the NUL terminator) or dstLen > SSIZE_MAX (the latter
+ * case being likely a negative number returned as an error and casted to unsigned) . Returns a
+ * pointer to the NUL terminator.
+ */
+char16_t *utf8_to_utf16(
+ const uint8_t* src, size_t srcLen, char16_t* dst, size_t dstLen);
+
+}
+
+#endif
diff --git a/libutils/binder/include/utils/Vector.h b/libutils/binder/include/utils/Vector.h
new file mode 100644
index 0000000..d5db3cb
--- /dev/null
+++ b/libutils/binder/include/utils/Vector.h
@@ -0,0 +1,418 @@
+/*
+ * Copyright (C) 2005 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.
+ */
+
+#ifndef ANDROID_VECTOR_H
+#define ANDROID_VECTOR_H
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <log/log.h>
+#include <utils/TypeHelpers.h>
+#include <utils/VectorImpl.h>
+#ifndef __has_attribute
+#define __has_attribute(x) 0
+#endif
+
+/*
+ * Used to exclude some functions from CFI.
+ */
+#if __has_attribute(no_sanitize)
+#define UTILS_VECTOR_NO_CFI __attribute__((no_sanitize("cfi")))
+#else
+#define UTILS_VECTOR_NO_CFI
+#endif
+
+// ---------------------------------------------------------------------------
+
+namespace android {
+
+template <typename TYPE>
+class SortedVector;
+
+/*!
+ * The main templated vector class ensuring type safety
+ * while making use of VectorImpl.
+ * This is the class users want to use.
+ *
+ * DO NOT USE: please use std::vector
+ */
+
+template <class TYPE>
+class Vector : private VectorImpl
+{
+public:
+ typedef TYPE value_type;
+
+ /*!
+ * Constructors and destructors
+ */
+
+ Vector();
+ Vector(const Vector<TYPE>& rhs);
+ explicit Vector(const SortedVector<TYPE>& rhs);
+ virtual ~Vector();
+
+ /*! copy operator */
+ Vector<TYPE>& operator=(const Vector<TYPE>& rhs); // NOLINT(cert-oop54-cpp)
+ Vector<TYPE>& operator=(const SortedVector<TYPE>& rhs); // NOLINT(cert-oop54-cpp)
+
+ /*
+ * empty the vector
+ */
+
+ inline void clear() { VectorImpl::clear(); }
+
+ /*!
+ * vector stats
+ */
+
+ //! returns number of items in the vector
+ inline size_t size() const { return VectorImpl::size(); }
+ //! returns whether or not the vector is empty
+ inline bool isEmpty() const { return VectorImpl::isEmpty(); }
+ //! returns how many items can be stored without reallocating the backing store
+ inline size_t capacity() const { return VectorImpl::capacity(); }
+ //! sets the capacity. capacity can never be reduced less than size()
+ inline ssize_t setCapacity(size_t size) { return VectorImpl::setCapacity(size); }
+
+ /*!
+ * set the size of the vector. items are appended with the default
+ * constructor, or removed from the end as needed.
+ */
+ inline ssize_t resize(size_t size) { return VectorImpl::resize(size); }
+
+ /*!
+ * C-style array access
+ */
+
+ //! read-only C-style access
+ inline const TYPE* array() const;
+ //! read-write C-style access
+ TYPE* editArray();
+
+ /*!
+ * accessors
+ */
+
+ //! read-only access to an item at a given index
+ inline const TYPE& operator [] (size_t index) const;
+ //! alternate name for operator []
+ inline const TYPE& itemAt(size_t index) const;
+ //! stack-usage of the vector. returns the top of the stack (last element)
+ const TYPE& top() const;
+
+ /*!
+ * modifying the array
+ */
+
+ //! copy-on write support, grants write access to an item
+ TYPE& editItemAt(size_t index);
+ //! grants right access to the top of the stack (last element)
+ TYPE& editTop();
+
+ /*!
+ * append/insert another vector
+ */
+
+ //! insert another vector at a given index
+ ssize_t insertVectorAt(const Vector<TYPE>& vector, size_t index);
+
+ //! append another vector at the end of this one
+ ssize_t appendVector(const Vector<TYPE>& vector);
+
+
+ //! insert an array at a given index
+ ssize_t insertArrayAt(const TYPE* array, size_t index, size_t length);
+
+ //! append an array at the end of this vector
+ ssize_t appendArray(const TYPE* array, size_t length);
+
+ /*!
+ * add/insert/replace items
+ */
+
+ //! insert one or several items initialized with their default constructor
+ inline ssize_t insertAt(size_t index, size_t numItems = 1);
+ //! insert one or several items initialized from a prototype item
+ ssize_t insertAt(const TYPE& prototype_item, size_t index, size_t numItems = 1);
+ //! pop the top of the stack (removes the last element). No-op if the stack's empty
+ inline void pop();
+ //! pushes an item initialized with its default constructor
+ inline void push();
+ //! pushes an item on the top of the stack
+ void push(const TYPE& item);
+ //! same as push() but returns the index the item was added at (or an error)
+ inline ssize_t add();
+ //! same as push() but returns the index the item was added at (or an error)
+ ssize_t add(const TYPE& item);
+ //! replace an item with a new one initialized with its default constructor
+ inline ssize_t replaceAt(size_t index);
+ //! replace an item with a new one
+ ssize_t replaceAt(const TYPE& item, size_t index);
+
+ /*!
+ * remove items
+ */
+
+ //! remove several items
+ inline ssize_t removeItemsAt(size_t index, size_t count = 1);
+ //! remove one item
+ inline ssize_t removeAt(size_t index) { return removeItemsAt(index); }
+
+ /*!
+ * sort (stable) the array
+ */
+
+ typedef int (*compar_t)(const TYPE* lhs, const TYPE* rhs);
+ typedef int (*compar_r_t)(const TYPE* lhs, const TYPE* rhs, void* state);
+
+ inline status_t sort(compar_t cmp);
+ inline status_t sort(compar_r_t cmp, void* state);
+
+ // for debugging only
+ inline size_t getItemSize() const { return itemSize(); }
+
+
+ /*
+ * these inlines add some level of compatibility with STL. eventually
+ * we should probably turn things around.
+ */
+ typedef TYPE* iterator;
+ typedef TYPE const* const_iterator;
+
+ inline iterator begin() { return editArray(); }
+ inline iterator end() { return editArray() + size(); }
+ inline const_iterator begin() const { return array(); }
+ inline const_iterator end() const { return array() + size(); }
+ inline void reserve(size_t n) { setCapacity(n); }
+ inline bool empty() const{ return isEmpty(); }
+ inline void push_back(const TYPE& item) { insertAt(item, size(), 1); }
+ inline void push_front(const TYPE& item) { insertAt(item, 0, 1); }
+ inline iterator erase(iterator pos) {
+ ssize_t index = removeItemsAt(static_cast<size_t>(pos-array()));
+ return begin() + index;
+ }
+
+protected:
+ virtual void do_construct(void* storage, size_t num) const;
+ virtual void do_destroy(void* storage, size_t num) const;
+ virtual void do_copy(void* dest, const void* from, size_t num) const;
+ virtual void do_splat(void* dest, const void* item, size_t num) const;
+ virtual void do_move_forward(void* dest, const void* from, size_t num) const;
+ virtual void do_move_backward(void* dest, const void* from, size_t num) const;
+};
+
+// ---------------------------------------------------------------------------
+// No user serviceable parts from here...
+// ---------------------------------------------------------------------------
+
+template<class TYPE> inline
+Vector<TYPE>::Vector()
+ : VectorImpl(sizeof(TYPE),
+ ((traits<TYPE>::has_trivial_ctor ? HAS_TRIVIAL_CTOR : 0)
+ |(traits<TYPE>::has_trivial_dtor ? HAS_TRIVIAL_DTOR : 0)
+ |(traits<TYPE>::has_trivial_copy ? HAS_TRIVIAL_COPY : 0))
+ )
+{
+}
+
+template<class TYPE> inline
+Vector<TYPE>::Vector(const Vector<TYPE>& rhs)
+ : VectorImpl(rhs) {
+}
+
+template<class TYPE> inline
+Vector<TYPE>::Vector(const SortedVector<TYPE>& rhs)
+ : VectorImpl(static_cast<const VectorImpl&>(rhs)) {
+}
+
+template<class TYPE> inline
+Vector<TYPE>::~Vector() {
+ finish_vector();
+}
+
+template <class TYPE>
+inline Vector<TYPE>& Vector<TYPE>::operator=(const Vector<TYPE>& rhs) // NOLINT(cert-oop54-cpp)
+{
+ VectorImpl::operator=(rhs);
+ return *this;
+}
+
+template <class TYPE>
+inline Vector<TYPE>& Vector<TYPE>::operator=(
+ const SortedVector<TYPE>& rhs) // NOLINT(cert-oop54-cpp)
+{
+ VectorImpl::operator=(static_cast<const VectorImpl&>(rhs));
+ return *this;
+}
+
+template<class TYPE> inline
+const TYPE* Vector<TYPE>::array() const {
+ return static_cast<const TYPE *>(arrayImpl());
+}
+
+template<class TYPE> inline
+TYPE* Vector<TYPE>::editArray() {
+ return static_cast<TYPE *>(editArrayImpl());
+}
+
+
+template<class TYPE> inline
+const TYPE& Vector<TYPE>::operator[](size_t index) const {
+ LOG_FATAL_IF(index>=size(),
+ "%s: index=%u out of range (%u)", __PRETTY_FUNCTION__,
+ int(index), int(size()));
+ return *(array() + index);
+}
+
+template<class TYPE> inline
+const TYPE& Vector<TYPE>::itemAt(size_t index) const {
+ return operator[](index);
+}
+
+template<class TYPE> inline
+const TYPE& Vector<TYPE>::top() const {
+ return *(array() + size() - 1);
+}
+
+template<class TYPE> inline
+TYPE& Vector<TYPE>::editItemAt(size_t index) {
+ return *( static_cast<TYPE *>(editItemLocation(index)) );
+}
+
+template<class TYPE> inline
+TYPE& Vector<TYPE>::editTop() {
+ return *( static_cast<TYPE *>(editItemLocation(size()-1)) );
+}
+
+template<class TYPE> inline
+ssize_t Vector<TYPE>::insertVectorAt(const Vector<TYPE>& vector, size_t index) {
+ return VectorImpl::insertVectorAt(reinterpret_cast<const VectorImpl&>(vector), index);
+}
+
+template<class TYPE> inline
+ssize_t Vector<TYPE>::appendVector(const Vector<TYPE>& vector) {
+ return VectorImpl::appendVector(reinterpret_cast<const VectorImpl&>(vector));
+}
+
+template<class TYPE> inline
+ssize_t Vector<TYPE>::insertArrayAt(const TYPE* array, size_t index, size_t length) {
+ return VectorImpl::insertArrayAt(array, index, length);
+}
+
+template<class TYPE> inline
+ssize_t Vector<TYPE>::appendArray(const TYPE* array, size_t length) {
+ return VectorImpl::appendArray(array, length);
+}
+
+template<class TYPE> inline
+ssize_t Vector<TYPE>::insertAt(const TYPE& item, size_t index, size_t numItems) {
+ return VectorImpl::insertAt(&item, index, numItems);
+}
+
+template<class TYPE> inline
+void Vector<TYPE>::push(const TYPE& item) {
+ return VectorImpl::push(&item);
+}
+
+template<class TYPE> inline
+ssize_t Vector<TYPE>::add(const TYPE& item) {
+ return VectorImpl::add(&item);
+}
+
+template<class TYPE> inline
+ssize_t Vector<TYPE>::replaceAt(const TYPE& item, size_t index) {
+ return VectorImpl::replaceAt(&item, index);
+}
+
+template<class TYPE> inline
+ssize_t Vector<TYPE>::insertAt(size_t index, size_t numItems) {
+ return VectorImpl::insertAt(index, numItems);
+}
+
+template<class TYPE> inline
+void Vector<TYPE>::pop() {
+ VectorImpl::pop();
+}
+
+template<class TYPE> inline
+void Vector<TYPE>::push() {
+ VectorImpl::push();
+}
+
+template<class TYPE> inline
+ssize_t Vector<TYPE>::add() {
+ return VectorImpl::add();
+}
+
+template<class TYPE> inline
+ssize_t Vector<TYPE>::replaceAt(size_t index) {
+ return VectorImpl::replaceAt(index);
+}
+
+template<class TYPE> inline
+ssize_t Vector<TYPE>::removeItemsAt(size_t index, size_t count) {
+ return VectorImpl::removeItemsAt(index, count);
+}
+
+template<class TYPE> inline
+status_t Vector<TYPE>::sort(Vector<TYPE>::compar_t cmp) {
+ return VectorImpl::sort(reinterpret_cast<VectorImpl::compar_t>(cmp));
+}
+
+template<class TYPE> inline
+status_t Vector<TYPE>::sort(Vector<TYPE>::compar_r_t cmp, void* state) {
+ return VectorImpl::sort(reinterpret_cast<VectorImpl::compar_r_t>(cmp), state);
+}
+
+// ---------------------------------------------------------------------------
+
+template<class TYPE>
+UTILS_VECTOR_NO_CFI void Vector<TYPE>::do_construct(void* storage, size_t num) const {
+ construct_type( reinterpret_cast<TYPE*>(storage), num );
+}
+
+template<class TYPE>
+void Vector<TYPE>::do_destroy(void* storage, size_t num) const {
+ destroy_type( reinterpret_cast<TYPE*>(storage), num );
+}
+
+template<class TYPE>
+UTILS_VECTOR_NO_CFI void Vector<TYPE>::do_copy(void* dest, const void* from, size_t num) const {
+ copy_type( reinterpret_cast<TYPE*>(dest), reinterpret_cast<const TYPE*>(from), num );
+}
+
+template<class TYPE>
+UTILS_VECTOR_NO_CFI void Vector<TYPE>::do_splat(void* dest, const void* item, size_t num) const {
+ splat_type( reinterpret_cast<TYPE*>(dest), reinterpret_cast<const TYPE*>(item), num );
+}
+
+template<class TYPE>
+UTILS_VECTOR_NO_CFI void Vector<TYPE>::do_move_forward(void* dest, const void* from, size_t num) const {
+ move_forward_type( reinterpret_cast<TYPE*>(dest), reinterpret_cast<const TYPE*>(from), num );
+}
+
+template<class TYPE>
+UTILS_VECTOR_NO_CFI void Vector<TYPE>::do_move_backward(void* dest, const void* from, size_t num) const {
+ move_backward_type( reinterpret_cast<TYPE*>(dest), reinterpret_cast<const TYPE*>(from), num );
+}
+
+} // namespace android
+
+// ---------------------------------------------------------------------------
+
+#endif // ANDROID_VECTOR_H
diff --git a/libutils/binder/include/utils/VectorImpl.h b/libutils/binder/include/utils/VectorImpl.h
new file mode 100644
index 0000000..41b9f33
--- /dev/null
+++ b/libutils/binder/include/utils/VectorImpl.h
@@ -0,0 +1,182 @@
+/*
+ * Copyright (C) 2005 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.
+ */
+
+#ifndef ANDROID_VECTOR_IMPL_H
+#define ANDROID_VECTOR_IMPL_H
+
+#include <assert.h>
+#include <stdint.h>
+#include <sys/types.h>
+#include <utils/Errors.h>
+
+// ---------------------------------------------------------------------------
+// No user serviceable parts in here...
+// ---------------------------------------------------------------------------
+
+namespace android {
+
+/*!
+ * Implementation of the guts of the vector<> class
+ * this ensures backward binary compatibility and
+ * reduces code size.
+ * For performance reasons, we expose mStorage and mCount
+ * so these fields are set in stone.
+ *
+ */
+
+class VectorImpl
+{
+public:
+ enum { // flags passed to the ctor
+ HAS_TRIVIAL_CTOR = 0x00000001,
+ HAS_TRIVIAL_DTOR = 0x00000002,
+ HAS_TRIVIAL_COPY = 0x00000004,
+ };
+
+ VectorImpl(size_t itemSize, uint32_t flags);
+ VectorImpl(const VectorImpl& rhs);
+ virtual ~VectorImpl();
+
+ /*! must be called from subclasses destructor */
+ void finish_vector();
+
+ VectorImpl& operator = (const VectorImpl& rhs);
+
+ /*! C-style array access */
+ inline const void* arrayImpl() const { return mStorage; }
+ void* editArrayImpl();
+
+ /*! vector stats */
+ inline size_t size() const { return mCount; }
+ inline bool isEmpty() const { return mCount == 0; }
+ size_t capacity() const;
+ ssize_t setCapacity(size_t size);
+ ssize_t resize(size_t size);
+
+ /*! append/insert another vector or array */
+ ssize_t insertVectorAt(const VectorImpl& vector, size_t index);
+ ssize_t appendVector(const VectorImpl& vector);
+ ssize_t insertArrayAt(const void* array, size_t index, size_t length);
+ ssize_t appendArray(const void* array, size_t length);
+
+ /*! add/insert/replace items */
+ ssize_t insertAt(size_t where, size_t numItems = 1);
+ ssize_t insertAt(const void* item, size_t where, size_t numItems = 1);
+ void pop();
+ void push();
+ void push(const void* item);
+ ssize_t add();
+ ssize_t add(const void* item);
+ ssize_t replaceAt(size_t index);
+ ssize_t replaceAt(const void* item, size_t index);
+
+ /*! remove items */
+ ssize_t removeItemsAt(size_t index, size_t count = 1);
+ void clear();
+
+ const void* itemLocation(size_t index) const;
+ void* editItemLocation(size_t index);
+
+ typedef int (*compar_t)(const void* lhs, const void* rhs);
+ typedef int (*compar_r_t)(const void* lhs, const void* rhs, void* state);
+ status_t sort(compar_t cmp);
+ status_t sort(compar_r_t cmp, void* state);
+
+protected:
+ size_t itemSize() const;
+ void release_storage();
+
+ virtual void do_construct(void* storage, size_t num) const = 0;
+ virtual void do_destroy(void* storage, size_t num) const = 0;
+ virtual void do_copy(void* dest, const void* from, size_t num) const = 0;
+ virtual void do_splat(void* dest, const void* item, size_t num) const = 0;
+ virtual void do_move_forward(void* dest, const void* from, size_t num) const = 0;
+ virtual void do_move_backward(void* dest, const void* from, size_t num) const = 0;
+
+private:
+ void* _grow(size_t where, size_t amount);
+ void _shrink(size_t where, size_t amount);
+
+ inline void _do_construct(void* storage, size_t num) const;
+ inline void _do_destroy(void* storage, size_t num) const;
+ inline void _do_copy(void* dest, const void* from, size_t num) const;
+ inline void _do_splat(void* dest, const void* item, size_t num) const;
+ inline void _do_move_forward(void* dest, const void* from, size_t num) const;
+ inline void _do_move_backward(void* dest, const void* from, size_t num) const;
+
+ // These 2 fields are exposed in the inlines below,
+ // so they're set in stone.
+ void * mStorage; // base address of the vector
+ size_t mCount; // number of items
+
+ const uint32_t mFlags;
+ const size_t mItemSize;
+};
+
+
+
+class SortedVectorImpl : public VectorImpl
+{
+public:
+ SortedVectorImpl(size_t itemSize, uint32_t flags);
+ explicit SortedVectorImpl(const VectorImpl& rhs);
+ virtual ~SortedVectorImpl();
+
+ SortedVectorImpl& operator = (const SortedVectorImpl& rhs);
+
+ //! finds the index of an item
+ ssize_t indexOf(const void* item) const;
+
+ //! finds where this item should be inserted
+ size_t orderOf(const void* item) const;
+
+ //! add an item in the right place (or replaces it if there is one)
+ ssize_t add(const void* item);
+
+ //! merges a vector into this one
+ ssize_t merge(const VectorImpl& vector);
+ ssize_t merge(const SortedVectorImpl& vector);
+
+ //! removes an item
+ ssize_t remove(const void* item);
+
+protected:
+ virtual int do_compare(const void* lhs, const void* rhs) const = 0;
+
+private:
+ ssize_t _indexOrderOf(const void* item, size_t* order = nullptr) const;
+
+ // these are made private, because they can't be used on a SortedVector
+ // (they don't have an implementation either)
+ ssize_t add();
+ void pop();
+ void push();
+ void push(const void* item);
+ ssize_t insertVectorAt(const VectorImpl& vector, size_t index);
+ ssize_t appendVector(const VectorImpl& vector);
+ ssize_t insertArrayAt(const void* array, size_t index, size_t length);
+ ssize_t appendArray(const void* array, size_t length);
+ ssize_t insertAt(size_t where, size_t numItems = 1);
+ ssize_t insertAt(const void* item, size_t where, size_t numItems = 1);
+ ssize_t replaceAt(size_t index);
+ ssize_t replaceAt(const void* item, size_t index);
+};
+
+} // namespace android
+
+// ---------------------------------------------------------------------------
+
+#endif // ANDROID_VECTOR_IMPL_H