Merge changes I68ed9d1c,I4ebccfd0,I3507bdfd,Iaf02f55c into cw-e-dev am: d6ad64f894
am: a20eb797c4
* commit 'a20eb797c462189ba6641308d80e638501db0a18':
system_server BINDER_TYPE_FD sockets using ashmem accessors
Parcel: file descriptor leak
Parcel: include Android coding standard
Parcel: LOG_TAG cleanup
diff --git a/Android.mk b/Android.mk
index d5860ef..bd432f3 100644
--- a/Android.mk
+++ b/Android.mk
@@ -36,6 +36,7 @@
PermissionCache.cpp \
ProcessState.cpp \
Static.cpp \
+ Status.cpp \
TextOutput.cpp \
LOCAL_PATH:= $(call my-dir)
diff --git a/Binder.cpp b/Binder.cpp
index 9d200fb..e39093d 100644
--- a/Binder.cpp
+++ b/Binder.cpp
@@ -16,7 +16,7 @@
#include <binder/Binder.h>
-#include <stdatomic.h>
+#include <atomic>
#include <utils/misc.h>
#include <binder/BpBinder.h>
#include <binder/IInterface.h>
@@ -70,9 +70,8 @@
// ---------------------------------------------------------------------------
-BBinder::BBinder()
+BBinder::BBinder() : mExtras(nullptr)
{
- atomic_init(&mExtras, static_cast<uintptr_t>(0));
}
bool BBinder::isBinderAlive() const
@@ -139,19 +138,16 @@
const void* objectID, void* object, void* cleanupCookie,
object_cleanup_func func)
{
- Extras* e = reinterpret_cast<Extras*>(
- atomic_load_explicit(&mExtras, memory_order_acquire));
+ Extras* e = mExtras.load(std::memory_order_acquire);
if (!e) {
e = new Extras;
- uintptr_t expected = 0;
- if (!atomic_compare_exchange_strong_explicit(
- &mExtras, &expected,
- reinterpret_cast<uintptr_t>(e),
- memory_order_release,
- memory_order_acquire)) {
+ Extras* expected = nullptr;
+ if (!mExtras.compare_exchange_strong(expected, e,
+ std::memory_order_release,
+ std::memory_order_acquire)) {
delete e;
- e = reinterpret_cast<Extras*>(expected); // Filled in by CAS
+ e = expected; // Filled in by CAS
}
if (e == 0) return; // out of memory
}
@@ -160,18 +156,9 @@
e->mObjects.attach(objectID, object, cleanupCookie, func);
}
-// The C11 standard doesn't allow atomic loads from const fields,
-// though C++11 does. Fudge it until standards get straightened out.
-static inline uintptr_t load_const_atomic(const atomic_uintptr_t* p,
- memory_order mo) {
- atomic_uintptr_t* non_const_p = const_cast<atomic_uintptr_t*>(p);
- return atomic_load_explicit(non_const_p, mo);
-}
-
void* BBinder::findObject(const void* objectID) const
{
- Extras* e = reinterpret_cast<Extras*>(
- load_const_atomic(&mExtras, memory_order_acquire));
+ Extras* e = mExtras.load(std::memory_order_acquire);
if (!e) return NULL;
AutoMutex _l(e->mLock);
@@ -180,8 +167,7 @@
void BBinder::detachObject(const void* objectID)
{
- Extras* e = reinterpret_cast<Extras*>(
- atomic_load_explicit(&mExtras, memory_order_acquire));
+ Extras* e = mExtras.load(std::memory_order_acquire);
if (!e) return;
AutoMutex _l(e->mLock);
@@ -195,8 +181,7 @@
BBinder::~BBinder()
{
- Extras* e = reinterpret_cast<Extras*>(
- atomic_load_explicit(&mExtras, memory_order_relaxed));
+ Extras* e = mExtras.load(std::memory_order_relaxed);
if (e) delete e;
}
@@ -252,7 +237,7 @@
BpRefBase::~BpRefBase()
{
if (mRemote) {
- if (!(mState&kRemoteAcquired)) {
+ if (!(mState.load(std::memory_order_relaxed)&kRemoteAcquired)) {
mRemote->decStrong(this);
}
mRefs->decWeak(this);
@@ -261,7 +246,7 @@
void BpRefBase::onFirstRef()
{
- android_atomic_or(kRemoteAcquired, &mState);
+ mState.fetch_or(kRemoteAcquired, std::memory_order_relaxed);
}
void BpRefBase::onLastStrongRef(const void* /*id*/)
diff --git a/Debug.cpp b/Debug.cpp
index bdb7182..a8f2da5 100644
--- a/Debug.cpp
+++ b/Debug.cpp
@@ -138,7 +138,7 @@
*pos = 0;
return pos;
}
-
+
if( fullContext ) {
*pos++ = '0';
*pos++ = 'x';
@@ -167,21 +167,21 @@
if (func == NULL) func = defaultPrintFunc;
size_t offset;
-
+
unsigned char *pos = (unsigned char *)buf;
-
+
if (pos == NULL) {
if (singleLineBytesCutoff < 0) func(cookie, "\n");
func(cookie, "(NULL)");
return;
}
-
+
if (length == 0) {
if (singleLineBytesCutoff < 0) func(cookie, "\n");
func(cookie, "(empty)");
return;
}
-
+
if ((int32_t)length < 0) {
if (singleLineBytesCutoff < 0) func(cookie, "\n");
char buf[64];
@@ -189,12 +189,12 @@
func(cookie, buf);
return;
}
-
+
char buffer[256];
static const size_t maxBytesPerLine = (sizeof(buffer)-1-11-4)/(3+1);
-
+
if (bytesPerLine > maxBytesPerLine) bytesPerLine = maxBytesPerLine;
-
+
const bool oneLine = (int32_t)length <= singleLineBytesCutoff;
bool newLine = false;
if (cStyle) {
@@ -205,7 +205,7 @@
func(cookie, "\n");
newLine = true;
}
-
+
for (offset = 0; ; offset += bytesPerLine, pos += bytesPerLine) {
long remain = length;
@@ -217,21 +217,20 @@
size_t index;
size_t word;
-
+
for (word = 0; word < bytesPerLine; ) {
const size_t startIndex = word+(alignment-(alignment?1:0));
- const ssize_t dir = -1;
for (index = 0; index < alignment || (alignment == 0 && index < bytesPerLine); index++) {
-
+
if (!cStyle) {
if (index == 0 && word > 0 && alignment > 0) {
*c++ = ' ';
}
-
+
if (remain-- > 0) {
- const unsigned char val = *(pos+startIndex+(index*dir));
+ const unsigned char val = *(pos+startIndex-index);
*c++ = makehexdigit(val>>4);
*c++ = makehexdigit(val);
} else if (!oneLine) {
@@ -248,14 +247,14 @@
*c++ = '0';
*c++ = 'x';
}
- const unsigned char val = *(pos+startIndex+(index*dir));
+ const unsigned char val = *(pos+startIndex-index);
*c++ = makehexdigit(val>>4);
*c++ = makehexdigit(val);
remain--;
}
}
}
-
+
word += index;
}
@@ -272,7 +271,7 @@
*c++ = ' ';
}
}
-
+
*c++ = '\'';
if (length > bytesPerLine) *c++ = '\n';
} else {
@@ -284,7 +283,7 @@
*c = 0;
func(cookie, buffer);
newLine = true;
-
+
if (length <= bytesPerLine) break;
length -= bytesPerLine;
}
diff --git a/Parcel.cpp b/Parcel.cpp
index 1429a5c..c481751 100644
--- a/Parcel.cpp
+++ b/Parcel.cpp
@@ -32,6 +32,7 @@
#include <binder/IPCThreadState.h>
#include <binder/Parcel.h>
#include <binder/ProcessState.h>
+#include <binder/Status.h>
#include <binder/TextOutput.h>
#include <cutils/ashmem.h>
@@ -71,9 +72,6 @@
// Note: must be kept in sync with android/os/StrictMode.java's PENALTY_GATHER
#define STRICT_MODE_PENALTY_GATHER (0x40 << 16)
-// Note: must be kept in sync with android/os/Parcel.java's EX_HAS_REPLY_HEADER
-#define EX_HAS_REPLY_HEADER -128
-
// XXX This can be made public if we want to provide
// support for typed data.
struct small_flat_data
@@ -346,6 +344,39 @@
return BAD_TYPE;
}
+namespace {
+
+template<typename T>
+status_t readTypedVector(std::vector<T>* val, const Parcel* p,
+ status_t(Parcel::*read_func)(T*) const) {
+ val->clear();
+
+ int32_t size;
+ status_t status = p->readInt32(&size);
+
+ if (status != OK) {
+ return status;
+ }
+
+ if (size < 0) {
+ return UNEXPECTED_NULL;
+ }
+
+ val->resize(size);
+
+ for (auto& v: *val) {
+ status = (p->*read_func)(&v);
+
+ if (status != OK) {
+ return status;
+ }
+ }
+
+ return OK;
+}
+
+} // namespace
+
// ---------------------------------------------------------------------------
Parcel::Parcel()
@@ -386,13 +417,11 @@
size_t Parcel::dataAvail() const
{
- // TODO: decide what to do about the possibility that this can
- // report an available-data size that exceeds a Java int's max
- // positive value, causing havoc. Fortunately this will only
- // happen if someone constructs a Parcel containing more than two
- // gigabytes of data, which on typical phone hardware is simply
- // not possible.
- return dataSize() - dataPosition();
+ size_t result = dataSize() - dataPosition();
+ if (result > INT32_MAX) {
+ abort();
+ }
+ return result;
}
size_t Parcel::dataPosition() const
@@ -753,6 +782,104 @@
return NULL;
}
+namespace {
+
+template<typename T, typename U>
+status_t unsafeWriteTypedVector(const std::vector<T>& val, Parcel* p,
+ status_t(Parcel::*write_func)(U)) {
+ if (val.size() > std::numeric_limits<int32_t>::max()) {
+ return BAD_VALUE;
+ }
+
+ status_t status = p->writeInt32(val.size());
+
+ if (status != OK) {
+ return status;
+ }
+
+ for (const auto& item : val) {
+ status = (p->*write_func)(item);
+
+ if (status != OK) {
+ return status;
+ }
+ }
+
+ return OK;
+}
+
+template<typename T>
+status_t writeTypedVector(const std::vector<T>& val, Parcel* p,
+ status_t(Parcel::*write_func)(const T&)) {
+ return unsafeWriteTypedVector(val, p, write_func);
+}
+
+template<typename T>
+status_t writeTypedVector(const std::vector<T>& val, Parcel* p,
+ status_t(Parcel::*write_func)(T)) {
+ return unsafeWriteTypedVector(val, p, write_func);
+}
+
+} // namespace
+
+status_t Parcel::writeByteVector(const std::vector<int8_t>& val)
+{
+ status_t status;
+ if (val.size() > std::numeric_limits<int32_t>::max()) {
+ status = BAD_VALUE;
+ return status;
+ }
+
+ status = writeInt32(val.size());
+ if (status != OK) {
+ return status;
+ }
+
+ void* data = writeInplace(val.size());
+ if (!data) {
+ status = BAD_VALUE;
+ return status;
+ }
+
+ memcpy(data, val.data(), val.size());
+ return status;
+}
+
+status_t Parcel::writeInt32Vector(const std::vector<int32_t>& val)
+{
+ return writeTypedVector(val, this, &Parcel::writeInt32);
+}
+
+status_t Parcel::writeInt64Vector(const std::vector<int64_t>& val)
+{
+ return writeTypedVector(val, this, &Parcel::writeInt64);
+}
+
+status_t Parcel::writeFloatVector(const std::vector<float>& val)
+{
+ return writeTypedVector(val, this, &Parcel::writeFloat);
+}
+
+status_t Parcel::writeDoubleVector(const std::vector<double>& val)
+{
+ return writeTypedVector(val, this, &Parcel::writeDouble);
+}
+
+status_t Parcel::writeBoolVector(const std::vector<bool>& val)
+{
+ return writeTypedVector(val, this, &Parcel::writeBool);
+}
+
+status_t Parcel::writeCharVector(const std::vector<char16_t>& val)
+{
+ return writeTypedVector(val, this, &Parcel::writeChar);
+}
+
+status_t Parcel::writeString16Vector(const std::vector<String16>& val)
+{
+ return writeTypedVector(val, this, &Parcel::writeString16);
+}
+
status_t Parcel::writeInt32(int32_t val)
{
return writeAligned(val);
@@ -796,6 +923,21 @@
return ret;
}
+status_t Parcel::writeBool(bool val)
+{
+ return writeInt32(int32_t(val));
+}
+
+status_t Parcel::writeChar(char16_t val)
+{
+ return writeInt32(int32_t(val));
+}
+
+status_t Parcel::writeByte(int8_t val)
+{
+ return writeInt32(int32_t(val));
+}
+
status_t Parcel::writeInt64(int64_t val)
{
return writeAligned(val);
@@ -882,6 +1024,15 @@
return flatten_binder(ProcessState::self(), val, this);
}
+status_t Parcel::writeStrongBinderVector(const std::vector<sp<IBinder>>& val)
+{
+ return writeTypedVector(val, this, &Parcel::writeStrongBinder);
+}
+
+status_t Parcel::readStrongBinderVector(std::vector<sp<IBinder>>* val) const {
+ return readTypedVector(val, this, &Parcel::readStrongBinder);
+}
+
status_t Parcel::writeWeakBinder(const wp<IBinder>& val)
{
return flatten_binder(ProcessState::self(), val, this);
@@ -1085,7 +1236,8 @@
status_t Parcel::writeNoException()
{
- return writeInt32(0);
+ binder::Status status;
+ return status.writeToParcel(this);
}
void Parcel::remove(size_t /*start*/, size_t /*amt*/)
@@ -1168,6 +1320,93 @@
return err;
}
+status_t Parcel::readByteVector(std::vector<int8_t>* val) const {
+ val->clear();
+
+ int32_t size;
+ status_t status = readInt32(&size);
+
+ if (status != OK) {
+ return status;
+ }
+
+ if (size < 0) {
+ status = UNEXPECTED_NULL;
+ return status;
+ }
+ if (size_t(size) > dataAvail()) {
+ status = BAD_VALUE;
+ return status;
+ }
+
+ const void* data = readInplace(size);
+ if (!data) {
+ status = BAD_VALUE;
+ return status;
+ }
+ val->resize(size);
+ memcpy(val->data(), data, size);
+
+ return status;
+}
+
+status_t Parcel::readInt32Vector(std::vector<int32_t>* val) const {
+ return readTypedVector(val, this, &Parcel::readInt32);
+}
+
+status_t Parcel::readInt64Vector(std::vector<int64_t>* val) const {
+ return readTypedVector(val, this, &Parcel::readInt64);
+}
+
+status_t Parcel::readFloatVector(std::vector<float>* val) const {
+ return readTypedVector(val, this, &Parcel::readFloat);
+}
+
+status_t Parcel::readDoubleVector(std::vector<double>* val) const {
+ return readTypedVector(val, this, &Parcel::readDouble);
+}
+
+status_t Parcel::readBoolVector(std::vector<bool>* val) const {
+ val->clear();
+
+ int32_t size;
+ status_t status = readInt32(&size);
+
+ if (status != OK) {
+ return status;
+ }
+
+ if (size < 0) {
+ return UNEXPECTED_NULL;
+ }
+
+ val->resize(size);
+
+ /* C++ bool handling means a vector of bools isn't necessarily addressable
+ * (we might use individual bits)
+ */
+ bool data;
+ for (int32_t i = 0; i < size; ++i) {
+ status = readBool(&data);
+ (*val)[i] = data;
+
+ if (status != OK) {
+ return status;
+ }
+ }
+
+ return OK;
+}
+
+status_t Parcel::readCharVector(std::vector<char16_t>* val) const {
+ return readTypedVector(val, this, &Parcel::readChar);
+}
+
+status_t Parcel::readString16Vector(std::vector<String16>* val) const {
+ return readTypedVector(val, this, &Parcel::readString16);
+}
+
+
status_t Parcel::readInt32(int32_t *pArg) const
{
return readAligned(pArg);
@@ -1286,6 +1525,44 @@
return readAligned<intptr_t>();
}
+status_t Parcel::readBool(bool *pArg) const
+{
+ int32_t tmp;
+ status_t ret = readInt32(&tmp);
+ *pArg = (tmp != 0);
+ return ret;
+}
+
+bool Parcel::readBool() const
+{
+ return readInt32() != 0;
+}
+
+status_t Parcel::readChar(char16_t *pArg) const
+{
+ int32_t tmp;
+ status_t ret = readInt32(&tmp);
+ *pArg = char16_t(tmp);
+ return ret;
+}
+
+char16_t Parcel::readChar() const
+{
+ return char16_t(readInt32());
+}
+
+status_t Parcel::readByte(int8_t *pArg) const
+{
+ int32_t tmp;
+ status_t ret = readInt32(&tmp);
+ *pArg = int8_t(tmp);
+ return ret;
+}
+
+int8_t Parcel::readByte() const
+{
+ return int8_t(readInt32());
+}
const char* Parcel::readCString() const
{
@@ -1324,6 +1601,19 @@
return String16();
}
+status_t Parcel::readString16(String16* pArg) const
+{
+ size_t len;
+ const char16_t* str = readString16Inplace(&len);
+ if (str) {
+ pArg->setTo(str, len);
+ return 0;
+ } else {
+ *pArg = String16();
+ return UNEXPECTED_NULL;
+ }
+}
+
const char16_t* Parcel::readString16Inplace(size_t* outLen) const
{
int32_t size = readInt32();
@@ -1339,10 +1629,15 @@
return NULL;
}
+status_t Parcel::readStrongBinder(sp<IBinder>* val) const
+{
+ return unflatten_binder(ProcessState::self(), *this, val);
+}
+
sp<IBinder> Parcel::readStrongBinder() const
{
sp<IBinder> val;
- unflatten_binder(ProcessState::self(), *this, &val);
+ readStrongBinder(&val);
return val;
}
@@ -1355,18 +1650,9 @@
int32_t Parcel::readExceptionCode() const
{
- int32_t exception_code = readAligned<int32_t>();
- if (exception_code == EX_HAS_REPLY_HEADER) {
- int32_t header_start = dataPosition();
- int32_t header_size = readAligned<int32_t>();
- // Skip over fat responses headers. Not used (or propagated) in
- // native code
- setDataPosition(header_start + header_size);
- // And fat response headers are currently only used when there are no
- // exceptions, so return no error:
- return 0;
- }
- return exception_code;
+ binder::Status status;
+ status.readFromParcel(*this);
+ return status.exceptionCode();
}
native_handle* Parcel::readNativeHandle() const
@@ -1679,8 +1965,14 @@
if (mData) {
LOG_ALLOC("Parcel %p: freeing with %zu capacity", this, mDataCapacity);
pthread_mutex_lock(&gParcelGlobalAllocSizeLock);
- gParcelGlobalAllocSize -= mDataCapacity;
- gParcelGlobalAllocCount--;
+ if (mDataCapacity <= gParcelGlobalAllocSize) {
+ gParcelGlobalAllocSize = gParcelGlobalAllocSize - mDataCapacity;
+ } else {
+ gParcelGlobalAllocSize = 0;
+ }
+ if (gParcelGlobalAllocCount > 0) {
+ gParcelGlobalAllocCount--;
+ }
pthread_mutex_unlock(&gParcelGlobalAllocSizeLock);
free(mData);
}
@@ -1859,6 +2151,7 @@
pthread_mutex_lock(&gParcelGlobalAllocSizeLock);
gParcelGlobalAllocSize += desired;
gParcelGlobalAllocSize -= mDataCapacity;
+ gParcelGlobalAllocCount++;
pthread_mutex_unlock(&gParcelGlobalAllocSizeLock);
mData = data;
mDataCapacity = desired;
diff --git a/Status.cpp b/Status.cpp
new file mode 100644
index 0000000..41fff3d
--- /dev/null
+++ b/Status.cpp
@@ -0,0 +1,133 @@
+/*
+ * 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 <binder/Status.h>
+
+namespace android {
+namespace binder {
+
+Status Status::fromExceptionCode(int32_t exception_code) {
+ return Status(exception_code, "");
+}
+
+Status Status::fromStatusT(status_t status) {
+ Status ret;
+ ret.setFromStatusT(status);
+ return ret;
+}
+
+Status Status::ok() {
+ return Status();
+}
+
+Status::Status(int32_t exception_code, const String8& message)
+ : mException(exception_code),
+ mMessage(message) {}
+
+Status::Status(int32_t exception_code, const char* message)
+ : mException(exception_code),
+ mMessage(message) {}
+
+status_t Status::readFromParcel(const Parcel& parcel) {
+ status_t status = parcel.readInt32(&mException);
+ if (status != OK) {
+ setFromStatusT(status);
+ return status;
+ }
+
+ // Skip over fat response headers. Not used (or propagated) in native code.
+ if (mException == EX_HAS_REPLY_HEADER) {
+ // Note that the header size includes the 4 byte size field.
+ const int32_t header_start = parcel.dataPosition();
+ int32_t header_size;
+ status = parcel.readInt32(&header_size);
+ if (status != OK) {
+ setFromStatusT(status);
+ return status;
+ }
+ parcel.setDataPosition(header_start + header_size);
+ // And fat response headers are currently only used when there are no
+ // exceptions, so act like there was no error.
+ mException = EX_NONE;
+ }
+
+ if (mException == EX_NONE) {
+ return status;
+ }
+
+ // The remote threw an exception. Get the message back.
+ mMessage = String8(parcel.readString16());
+
+ return status;
+}
+
+status_t Status::writeToParcel(Parcel* parcel) const {
+ status_t status = parcel->writeInt32(mException);
+ if (status != OK) { return status; }
+ if (mException == EX_NONE) {
+ // We have no more information to write.
+ return status;
+ }
+ status = parcel->writeString16(String16(mMessage));
+ return status;
+}
+
+void Status::setFromStatusT(status_t status) {
+ switch (status) {
+ case NO_ERROR:
+ mException = EX_NONE;
+ mMessage.clear();
+ break;
+ case UNEXPECTED_NULL:
+ mException = EX_NULL_POINTER;
+ mMessage.setTo("Unexpected null reference in Parcel");
+ break;
+ default:
+ mException = EX_TRANSACTION_FAILED;
+ mMessage.setTo("Transaction failed");
+ break;
+ }
+}
+
+void Status::setException(int32_t ex, const String8& message) {
+ mException = ex;
+ mMessage.setTo(message);
+}
+
+void Status::getException(int32_t* returned_exception,
+ String8* returned_message) const {
+ if (returned_exception) {
+ *returned_exception = mException;
+ }
+ if (returned_message) {
+ returned_message->setTo(mMessage);
+ }
+}
+
+String8 Status::toString8() const {
+ String8 ret;
+ if (mException == EX_NONE) {
+ ret.append("No error");
+ } else {
+ ret.appendFormat("Status(%d): '", mException);
+ ret.append(String8(mMessage));
+ ret.append("'");
+ }
+ return ret;
+}
+
+} // namespace binder
+} // namespace android
diff --git a/include/hwbinder/Binder.h b/include/hwbinder/Binder.h
index 86628a0..f849fd4 100644
--- a/include/hwbinder/Binder.h
+++ b/include/hwbinder/Binder.h
@@ -17,7 +17,7 @@
#ifndef ANDROID_BINDER_H
#define ANDROID_BINDER_H
-#include <stdatomic.h>
+#include <atomic>
#include <stdint.h>
#include <binder/IBinder.h>
@@ -71,7 +71,7 @@
class Extras;
- atomic_uintptr_t mExtras; // should be atomic<Extras *>
+ std::atomic<Extras*> mExtras;
void* mReserved0;
};
@@ -95,7 +95,7 @@
IBinder* const mRemote;
RefBase::weakref_type* mRefs;
- volatile int32_t mState;
+ std::atomic<int32_t> mState;
};
}; // namespace android
diff --git a/include/hwbinder/Parcel.h b/include/hwbinder/Parcel.h
index 16cd6cf..430c3ff 100644
--- a/include/hwbinder/Parcel.h
+++ b/include/hwbinder/Parcel.h
@@ -17,6 +17,8 @@
#ifndef ANDROID_PARCEL_H
#define ANDROID_PARCEL_H
+#include <vector>
+
#include <cutils/native_handle.h>
#include <utils/Errors.h>
#include <utils/RefBase.h>
@@ -25,6 +27,8 @@
#include <utils/Flattenable.h>
#include <linux/binder.h>
+#include <binder/IInterface.h>
+
// ---------------------------------------------------------------------------
namespace android {
@@ -108,6 +112,20 @@
status_t writeWeakBinder(const wp<IBinder>& val);
status_t writeInt32Array(size_t len, const int32_t *val);
status_t writeByteArray(size_t len, const uint8_t *val);
+ status_t writeBool(bool val);
+ status_t writeChar(char16_t val);
+ status_t writeByte(int8_t val);
+
+ status_t writeByteVector(const std::vector<int8_t>& val);
+ status_t writeInt32Vector(const std::vector<int32_t>& val);
+ status_t writeInt64Vector(const std::vector<int64_t>& val);
+ status_t writeFloatVector(const std::vector<float>& val);
+ status_t writeDoubleVector(const std::vector<double>& val);
+ status_t writeBoolVector(const std::vector<bool>& val);
+ status_t writeCharVector(const std::vector<char16_t>& val);
+ status_t writeString16Vector(const std::vector<String16>& val);
+
+ status_t writeStrongBinderVector(const std::vector<sp<IBinder>>& val);
template<typename T>
status_t write(const Flattenable<T>& val);
@@ -118,7 +136,7 @@
// Place a native_handle into the parcel (the native_handle's file-
// descriptors are dup'ed, so it is safe to delete the native_handle
- // when this function returns).
+ // when this function returns).
// Doesn't take ownership of the native_handle.
status_t writeNativeHandle(const native_handle* handle);
@@ -169,15 +187,37 @@
status_t readDouble(double *pArg) const;
intptr_t readIntPtr() const;
status_t readIntPtr(intptr_t *pArg) const;
+ bool readBool() const;
+ status_t readBool(bool *pArg) const;
+ char16_t readChar() const;
+ status_t readChar(char16_t *pArg) const;
+ int8_t readByte() const;
+ status_t readByte(int8_t *pArg) const;
const char* readCString() const;
String8 readString8() const;
String16 readString16() const;
+ status_t readString16(String16* pArg) const;
const char16_t* readString16Inplace(size_t* outLen) const;
sp<IBinder> readStrongBinder() const;
+ status_t readStrongBinder(sp<IBinder>* val) const;
wp<IBinder> readWeakBinder() const;
template<typename T>
+ status_t readStrongBinder(sp<T>* val) const;
+
+ status_t readStrongBinderVector(std::vector<sp<IBinder>>* val) const;
+
+ status_t readByteVector(std::vector<int8_t>* val) const;
+ status_t readInt32Vector(std::vector<int32_t>* val) const;
+ status_t readInt64Vector(std::vector<int64_t>* val) const;
+ status_t readFloatVector(std::vector<float>* val) const;
+ status_t readDoubleVector(std::vector<double>* val) const;
+ status_t readBoolVector(std::vector<bool>* val) const;
+ status_t readCharVector(std::vector<char16_t>* val) const;
+ status_t readString16Vector(std::vector<String16>* val) const;
+
+ template<typename T>
status_t read(Flattenable<T>& val) const;
template<typename T>
@@ -402,6 +442,22 @@
return NO_ERROR;
}
+template<typename T>
+status_t Parcel::readStrongBinder(sp<T>* val) const {
+ sp<IBinder> tmp;
+ status_t ret = readStrongBinder(&tmp);
+
+ if (ret == OK) {
+ *val = interface_cast<T>(tmp);
+
+ if (val->get() == nullptr) {
+ return UNKNOWN_ERROR;
+ }
+ }
+
+ return ret;
+}
+
// ---------------------------------------------------------------------------
inline TextOutput& operator<<(TextOutput& to, const Parcel& parcel)
diff --git a/include/hwbinder/Status.h b/include/hwbinder/Status.h
new file mode 100644
index 0000000..04738f8
--- /dev/null
+++ b/include/hwbinder/Status.h
@@ -0,0 +1,121 @@
+/*
+ * 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.
+ */
+
+#ifndef ANDROID_BINDER_STATUS_H
+#define ANDROID_BINDER_STATUS_H
+
+#include <cstdint>
+
+#include <binder/Parcel.h>
+#include <utils/String8.h>
+
+namespace android {
+namespace binder {
+
+// An object similar in function to a status_t except that it understands
+// how exceptions are encoded in the prefix of a Parcel. Used like:
+//
+// Parcel data;
+// Parcel reply;
+// status_t status;
+// binder::Status remote_exception;
+// if ((status = data.writeInterfaceToken(interface_descriptor)) != OK ||
+// (status = data.writeInt32(function_input)) != OK) {
+// // We failed to write into the memory of our local parcel?
+// }
+// if ((status = remote()->transact(transaction, data, &reply)) != OK) {
+// // Something has gone wrong in the binder driver or libbinder.
+// }
+// if ((status = remote_exception.readFromParcel(reply)) != OK) {
+// // The remote didn't correctly write the exception header to the
+// // reply.
+// }
+// if (!remote_exception.isOk()) {
+// // The transaction went through correctly, but the remote reported an
+// // exception during handling.
+// }
+//
+class Status final {
+public:
+ // Keep the exception codes in sync with android/os/Parcel.java.
+ enum Exception {
+ EX_NONE = 0,
+ EX_SECURITY = -1,
+ EX_BAD_PARCELABLE = -2,
+ EX_ILLEGAL_ARGUMENT = -3,
+ EX_NULL_POINTER = -4,
+ EX_ILLEGAL_STATE = -5,
+ EX_NETWORK_MAIN_THREAD = -6,
+ EX_UNSUPPORTED_OPERATION = -7,
+ EX_TRANSACTION_FAILED = -8,
+
+ // This is special and Java specific; see Parcel.java.
+ EX_HAS_REPLY_HEADER = -128,
+ };
+
+ // Allow authors to explicitly pick whether their integer is a status_t or
+ // exception code.
+ static Status fromExceptionCode(int32_t exception_code);
+ static Status fromStatusT(status_t status);
+ // A more readable alias for the default constructor.
+ static Status ok();
+
+ Status() = default;
+ Status(int32_t exception_code, const String8& message);
+ Status(int32_t exception_code, const char* message);
+
+
+ // Status objects are copyable and contain just simple data.
+ Status(const Status& status) = default;
+ Status(Status&& status) = default;
+ Status& operator=(const Status& status) = default;
+
+ ~Status() = default;
+
+ // Bear in mind that if the client or service is a Java endpoint, this
+ // is not the logic which will provide/interpret the data here.
+ status_t readFromParcel(const Parcel& parcel);
+ status_t writeToParcel(Parcel* parcel) const;
+
+ // Set one of the pre-defined exception types defined above.
+ void setException(int32_t ex, const String8& message);
+ // A few of the status_t values map to exception codes, but most of them
+ // simply map to "transaction failed."
+ void setFromStatusT(status_t status);
+
+ // Get information about an exception.
+ // Any argument may be given as nullptr.
+ void getException(int32_t* returned_exception,
+ String8* returned_message) const;
+ int32_t exceptionCode() const { return mException; }
+ const String8& exceptionMessage() const { return mMessage; }
+
+ bool isOk() const { return mException == EX_NONE; }
+
+ // For logging.
+ String8 toString8() const;
+
+private:
+ // We always write |mException| to the parcel.
+ // If |mException| != EX_NONE, we write message as well.
+ int32_t mException = EX_NONE;
+ String8 mMessage;
+}; // class Status
+
+} // namespace binder
+} // namespace android
+
+#endif // ANDROID_BINDER_STATUS_H