Merge "Declare ownership of native_handle_t object"
diff --git a/cmds/installd/commands.c b/cmds/installd/commands.c
index 12e8cd1..669f403 100644
--- a/cmds/installd/commands.c
+++ b/cmds/installd/commands.c
@@ -1235,31 +1235,82 @@
return -1;
}
-int restorecon_data()
+int restorecon_data(const char* pkgName, const char* seinfo, uid_t uid)
{
- char *data_dir = build_string2(android_data_dir.path, PRIMARY_USER_PREFIX);
- char *user_dir = build_string2(android_data_dir.path, SECONDARY_USER_PREFIX);
-
- unsigned int flags = SELINUX_ANDROID_RESTORECON_RECURSE |
- SELINUX_ANDROID_RESTORECON_DATADATA;
-
+ struct dirent *entry;
+ DIR *d;
+ struct stat s;
+ char *userdir;
+ char *primarydir;
+ char *pkgdir;
int ret = 0;
- if (!data_dir || !user_dir) {
+ // SELINUX_ANDROID_RESTORECON_DATADATA flag is set by libselinux. Not needed here.
+ unsigned int flags = SELINUX_ANDROID_RESTORECON_RECURSE;
+
+ if (!pkgName || !seinfo) {
+ ALOGE("Package name or seinfo tag is null when trying to restorecon.");
return -1;
}
- if (selinux_android_restorecon(data_dir, flags) < 0) {
- ALOGE("restorecon failed for %s: %s\n", data_dir, strerror(errno));
+ if (asprintf(&primarydir, "%s%s%s", android_data_dir.path, PRIMARY_USER_PREFIX, pkgName) < 0) {
+ return -1;
+ }
+
+ // Relabel for primary user.
+ if (selinux_android_restorecon_pkgdir(primarydir, seinfo, uid, flags) < 0) {
+ ALOGE("restorecon failed for %s: %s\n", primarydir, strerror(errno));
ret |= -1;
}
- if (selinux_android_restorecon(user_dir, flags) < 0) {
- ALOGE("restorecon failed for %s: %s\n", user_dir, strerror(errno));
- ret |= -1;
+ if (asprintf(&userdir, "%s%s", android_data_dir.path, SECONDARY_USER_PREFIX) < 0) {
+ free(primarydir);
+ return -1;
}
- free(data_dir);
- free(user_dir);
+ // Relabel package directory for all secondary users.
+ d = opendir(userdir);
+ if (d == NULL) {
+ free(primarydir);
+ free(userdir);
+ return -1;
+ }
+
+ while ((entry = readdir(d))) {
+ if (entry->d_type != DT_DIR) {
+ continue;
+ }
+
+ const char *user = entry->d_name;
+ // Ignore "." and ".."
+ if (!strcmp(user, ".") || !strcmp(user, "..")) {
+ continue;
+ }
+
+ // user directories start with a number
+ if (user[0] < '0' || user[0] > '9') {
+ ALOGE("Expecting numbered directory during restorecon. Instead got '%s'.", user);
+ continue;
+ }
+
+ if (asprintf(&pkgdir, "%s%s/%s", userdir, user, pkgName) < 0) {
+ continue;
+ }
+
+ if (stat(pkgdir, &s) < 0) {
+ free(pkgdir);
+ continue;
+ }
+
+ if (selinux_android_restorecon_pkgdir(pkgdir, seinfo, uid, flags) < 0) {
+ ALOGE("restorecon failed for %s: %s\n", pkgdir, strerror(errno));
+ ret |= -1;
+ }
+ free(pkgdir);
+ }
+
+ closedir(d);
+ free(primarydir);
+ free(userdir);
return ret;
}
diff --git a/cmds/installd/installd.c b/cmds/installd/installd.c
index 40fc13f..a078e1c 100644
--- a/cmds/installd/installd.c
+++ b/cmds/installd/installd.c
@@ -129,10 +129,10 @@
return idmap(arg[0], arg[1], atoi(arg[2]));
}
-static int do_restorecon_data(char **arg __attribute__((unused)),
- char reply[REPLY_MAX] __attribute__((unused)))
+static int do_restorecon_data(char **arg, char reply[REPLY_MAX] __attribute__((unused)))
{
- return restorecon_data();
+ return restorecon_data(arg[0], arg[1], atoi(arg[2]));
+ /* pkgName, seinfo, uid*/
}
struct cmdinfo {
@@ -159,7 +159,7 @@
{ "mkuserdata", 4, do_mk_user_data },
{ "rmuser", 1, do_rm_user },
{ "idmap", 3, do_idmap },
- { "restorecondata", 0, do_restorecon_data },
+ { "restorecondata", 3, do_restorecon_data },
};
static int readx(int s, void *_buf, int count)
@@ -541,6 +541,27 @@
}
}
+static int log_callback(int type, const char *fmt, ...) {
+ va_list ap;
+ int priority;
+
+ switch (type) {
+ case SELINUX_WARNING:
+ priority = ANDROID_LOG_WARN;
+ break;
+ case SELINUX_INFO:
+ priority = ANDROID_LOG_INFO;
+ break;
+ default:
+ priority = ANDROID_LOG_ERROR;
+ break;
+ }
+ va_start(ap, fmt);
+ LOG_PRI_VA(priority, "SELinux", fmt, ap);
+ va_end(ap);
+ return 0;
+}
+
int main(const int argc, const char *argv[]) {
char buf[BUFFER_MAX];
struct sockaddr addr;
@@ -550,6 +571,10 @@
ALOGI("installd firing up\n");
+ union selinux_callback cb;
+ cb.func_log = log_callback;
+ selinux_set_callback(SELINUX_CB_LOG, cb);
+
if (initialize_globals() < 0) {
ALOGE("Could not initialize globals; exiting.\n");
exit(1);
diff --git a/include/binder/MemoryDealer.h b/include/binder/MemoryDealer.h
index 170f20d..aa415d5 100644
--- a/include/binder/MemoryDealer.h
+++ b/include/binder/MemoryDealer.h
@@ -34,7 +34,8 @@
class MemoryDealer : public RefBase
{
public:
- MemoryDealer(size_t size, const char* name = 0);
+ MemoryDealer(size_t size, const char* name = 0,
+ uint32_t flags = 0 /* or bits such as MemoryHeapBase::READ_ONLY */ );
virtual sp<IMemory> allocate(size_t size);
virtual void deallocate(size_t offset);
diff --git a/include/media/drm/DrmAPI.h b/include/media/drm/DrmAPI.h
index 95bdf77..fc6b49c 100644
--- a/include/media/drm/DrmAPI.h
+++ b/include/media/drm/DrmAPI.h
@@ -178,12 +178,16 @@
// provisioning server.
//
// If successful, the opaque provision request blob is returned to the caller.
- virtual status_t getProvisionRequest(Vector<uint8_t> &request,
+ virtual status_t getProvisionRequest(String8 const &cert_type,
+ String8 const &cert_authority,
+ Vector<uint8_t> &request,
String8 &defaultUrl) = 0;
// After a provision response is received by the app, it is provided to the
// Drm plugin using provideProvisionResponse.
- virtual status_t provideProvisionResponse(Vector<uint8_t> const &response) = 0;
+ virtual status_t provideProvisionResponse(Vector<uint8_t> const &response,
+ Vector<uint8_t> &certificate,
+ Vector<uint8_t> &wrapped_key) = 0;
// A means of enforcing the contractual requirement for a concurrent stream
// limit per subscriber across devices is provided via SecureStop. SecureStop
@@ -290,6 +294,15 @@
bool &match) = 0;
+ // Compute an RSA signature on the provided message using the algorithm
+ // specified by algorithm.
+ virtual status_t signRSA(Vector<uint8_t> const &sessionId,
+ String8 const &algorithm,
+ Vector<uint8_t> const &message,
+ Vector<uint8_t> const &wrapped_key,
+ Vector<uint8_t> &signature) = 0;
+
+
status_t setListener(const sp<DrmPluginListener>& listener) {
Mutex::Autolock lock(mEventLock);
mListener = listener;
diff --git a/libs/binder/MemoryDealer.cpp b/libs/binder/MemoryDealer.cpp
index a14c100..8739625 100644
--- a/libs/binder/MemoryDealer.cpp
+++ b/libs/binder/MemoryDealer.cpp
@@ -225,8 +225,8 @@
// ----------------------------------------------------------------------------
-MemoryDealer::MemoryDealer(size_t size, const char* name)
- : mHeap(new MemoryHeapBase(size, 0, name)),
+MemoryDealer::MemoryDealer(size_t size, const char* name, uint32_t flags)
+ : mHeap(new MemoryHeapBase(size, flags, name)),
mAllocator(new SimpleBestFitAllocator(size))
{
}
diff --git a/libs/gui/BufferQueueProducer.cpp b/libs/gui/BufferQueueProducer.cpp
index 7db344a..9dd90ba 100644
--- a/libs/gui/BufferQueueProducer.cpp
+++ b/libs/gui/BufferQueueProducer.cpp
@@ -432,6 +432,7 @@
mSlots[*outSlot].mBufferState = BufferSlot::DEQUEUED;
mSlots[*outSlot].mEglFence = EGL_NO_SYNC_KHR;
mSlots[*outSlot].mFence = Fence::NO_FENCE;
+ mSlots[*outSlot].mRequestBufferCalled = true;
return returnFlags;
}
diff --git a/libs/gui/IGraphicBufferConsumer.cpp b/libs/gui/IGraphicBufferConsumer.cpp
index d3dffdd..1b19626 100644
--- a/libs/gui/IGraphicBufferConsumer.cpp
+++ b/libs/gui/IGraphicBufferConsumer.cpp
@@ -71,11 +71,11 @@
size_t c = 0;
if (mGraphicBuffer != 0) {
c += mGraphicBuffer->getFlattenedSize();
- FlattenableUtils::align<4>(c);
+ c = FlattenableUtils::align<4>(c);
}
if (mFence != 0) {
c += mFence->getFlattenedSize();
- FlattenableUtils::align<4>(c);
+ c = FlattenableUtils::align<4>(c);
}
return sizeof(int32_t) + c + getPodSize();
}
@@ -91,11 +91,21 @@
return c;
}
+static void writeBoolAsInt(void*& buffer, size_t& size, bool b) {
+ FlattenableUtils::write(buffer, size, static_cast<int32_t>(b));
+}
+
+static bool readBoolFromInt(void const*& buffer, size_t& size) {
+ int32_t i;
+ FlattenableUtils::read(buffer, size, i);
+ return static_cast<bool>(i);
+}
+
status_t IGraphicBufferConsumer::BufferItem::flatten(
void*& buffer, size_t& size, int*& fds, size_t& count) const {
// make sure we have enough space
- if (count < BufferItem::getFlattenedSize()) {
+ if (size < BufferItem::getFlattenedSize()) {
return NO_MEMORY;
}
@@ -128,12 +138,12 @@
FlattenableUtils::write(buffer, size, mTransform);
FlattenableUtils::write(buffer, size, mScalingMode);
FlattenableUtils::write(buffer, size, mTimestamp);
- FlattenableUtils::write(buffer, size, mIsAutoTimestamp);
+ writeBoolAsInt(buffer, size, mIsAutoTimestamp);
FlattenableUtils::write(buffer, size, mFrameNumber);
FlattenableUtils::write(buffer, size, mBuf);
- FlattenableUtils::write(buffer, size, mIsDroppable);
- FlattenableUtils::write(buffer, size, mAcquireCalled);
- FlattenableUtils::write(buffer, size, mTransformToDisplayInverse);
+ writeBoolAsInt(buffer, size, mIsDroppable);
+ writeBoolAsInt(buffer, size, mAcquireCalled);
+ writeBoolAsInt(buffer, size, mTransformToDisplayInverse);
return NO_ERROR;
}
@@ -170,12 +180,12 @@
FlattenableUtils::read(buffer, size, mTransform);
FlattenableUtils::read(buffer, size, mScalingMode);
FlattenableUtils::read(buffer, size, mTimestamp);
- FlattenableUtils::read(buffer, size, mIsAutoTimestamp);
+ mIsAutoTimestamp = readBoolFromInt(buffer, size);
FlattenableUtils::read(buffer, size, mFrameNumber);
FlattenableUtils::read(buffer, size, mBuf);
- FlattenableUtils::read(buffer, size, mIsDroppable);
- FlattenableUtils::read(buffer, size, mAcquireCalled);
- FlattenableUtils::read(buffer, size, mTransformToDisplayInverse);
+ mIsDroppable = readBoolFromInt(buffer, size);
+ mAcquireCalled = readBoolFromInt(buffer, size);
+ mTransformToDisplayInverse = readBoolFromInt(buffer, size);
return NO_ERROR;
}
diff --git a/libs/gui/tests/BufferQueue_test.cpp b/libs/gui/tests/BufferQueue_test.cpp
index 5aa34a5..7943476 100644
--- a/libs/gui/tests/BufferQueue_test.cpp
+++ b/libs/gui/tests/BufferQueue_test.cpp
@@ -24,7 +24,9 @@
#include <ui/GraphicBuffer.h>
+#include <binder/IPCThreadState.h>
#include <binder/IServiceManager.h>
+#include <binder/ProcessState.h>
#include <gui/BufferQueue.h>
namespace android {
@@ -32,20 +34,12 @@
class BufferQueueTest : public ::testing::Test {
public:
- static const String16 PRODUCER_NAME;
- static const String16 CONSUMER_NAME;
-
protected:
BufferQueueTest() {
const ::testing::TestInfo* const testInfo =
::testing::UnitTest::GetInstance()->current_test_info();
ALOGV("Begin test: %s.%s", testInfo->test_case_name(),
testInfo->name());
-
- BufferQueue::createBufferQueue(&mProducer, &mConsumer);
- sp<IServiceManager> serviceManager = defaultServiceManager();
- serviceManager->addService(PRODUCER_NAME, mProducer.get());
- serviceManager->addService(CONSUMER_NAME, mConsumer.get());
}
~BufferQueueTest() {
@@ -62,12 +56,13 @@
ASSERT_GE(*bufferCount, 0);
}
- sp<BnGraphicBufferProducer> mProducer;
- sp<BnGraphicBufferConsumer> mConsumer;
-};
+ void createBufferQueue() {
+ BufferQueue::createBufferQueue(&mProducer, &mConsumer);
+ }
-const String16 BufferQueueTest::PRODUCER_NAME = String16("BQTestProducer");
-const String16 BufferQueueTest::CONSUMER_NAME = String16("BQTestConsumer");
+ sp<IGraphicBufferProducer> mProducer;
+ sp<IGraphicBufferConsumer> mConsumer;
+};
struct DummyConsumer : public BnConsumerListener {
virtual void onFrameAvailable() {}
@@ -75,7 +70,74 @@
virtual void onSidebandStreamChanged() {}
};
+// XXX: Tests that fork a process to hold the BufferQueue must run before tests
+// that use a local BufferQueue, or else Binder will get unhappy
+TEST_F(BufferQueueTest, BufferQueueInAnotherProcess) {
+ const String16 PRODUCER_NAME = String16("BQTestProducer");
+ const String16 CONSUMER_NAME = String16("BQTestConsumer");
+
+ pid_t forkPid = fork();
+ ASSERT_NE(forkPid, -1);
+
+ if (forkPid == 0) {
+ // Child process
+ sp<BnGraphicBufferProducer> producer;
+ sp<BnGraphicBufferConsumer> consumer;
+ BufferQueue::createBufferQueue(&producer, &consumer);
+ sp<IServiceManager> serviceManager = defaultServiceManager();
+ serviceManager->addService(PRODUCER_NAME, producer.get());
+ serviceManager->addService(CONSUMER_NAME, consumer.get());
+ ProcessState::self()->startThreadPool();
+ IPCThreadState::self()->joinThreadPool();
+ LOG_ALWAYS_FATAL("Shouldn't be here");
+ }
+
+ sp<IServiceManager> serviceManager = defaultServiceManager();
+ sp<IBinder> binderProducer =
+ serviceManager->getService(PRODUCER_NAME);
+ mProducer = interface_cast<IGraphicBufferProducer>(binderProducer);
+ EXPECT_TRUE(mProducer != NULL);
+ sp<IBinder> binderConsumer =
+ serviceManager->getService(CONSUMER_NAME);
+ mConsumer = interface_cast<IGraphicBufferConsumer>(binderConsumer);
+ EXPECT_TRUE(mConsumer != NULL);
+
+ sp<DummyConsumer> dc(new DummyConsumer);
+ ASSERT_EQ(OK, mConsumer->consumerConnect(dc, false));
+ IGraphicBufferProducer::QueueBufferOutput output;
+ ASSERT_EQ(OK,
+ mProducer->connect(NULL, NATIVE_WINDOW_API_CPU, false, &output));
+
+ int slot;
+ sp<Fence> fence;
+ sp<GraphicBuffer> buffer;
+ ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION,
+ mProducer->dequeueBuffer(&slot, &fence, false, 0, 0, 0,
+ GRALLOC_USAGE_SW_WRITE_OFTEN));
+ ASSERT_EQ(OK, mProducer->requestBuffer(slot, &buffer));
+
+ uint32_t* dataIn;
+ ASSERT_EQ(OK, buffer->lock(GraphicBuffer::USAGE_SW_WRITE_OFTEN,
+ reinterpret_cast<void**>(&dataIn)));
+ *dataIn = 0x12345678;
+ ASSERT_EQ(OK, buffer->unlock());
+
+ IGraphicBufferProducer::QueueBufferInput input(0, false, Rect(0, 0, 1, 1),
+ NATIVE_WINDOW_SCALING_MODE_FREEZE, 0, false, Fence::NO_FENCE);
+ ASSERT_EQ(OK, mProducer->queueBuffer(slot, input, &output));
+
+ IGraphicBufferConsumer::BufferItem item;
+ ASSERT_EQ(OK, mConsumer->acquireBuffer(&item, 0));
+
+ uint32_t* dataOut;
+ ASSERT_EQ(OK, item.mGraphicBuffer->lock(GraphicBuffer::USAGE_SW_READ_OFTEN,
+ reinterpret_cast<void**>(&dataOut)));
+ ASSERT_EQ(*dataOut, 0x12345678);
+ ASSERT_EQ(OK, item.mGraphicBuffer->unlock());
+}
+
TEST_F(BufferQueueTest, AcquireBuffer_ExceedsMaxAcquireCount_Fails) {
+ createBufferQueue();
sp<DummyConsumer> dc(new DummyConsumer);
mConsumer->consumerConnect(dc, false);
IGraphicBufferProducer::QueueBufferOutput qbo;
@@ -109,6 +171,7 @@
}
TEST_F(BufferQueueTest, SetMaxAcquiredBufferCountWithIllegalValues_ReturnsError) {
+ createBufferQueue();
sp<DummyConsumer> dc(new DummyConsumer);
mConsumer->consumerConnect(dc, false);
@@ -125,6 +188,7 @@
}
TEST_F(BufferQueueTest, SetMaxAcquiredBufferCountWithLegalValues_Succeeds) {
+ createBufferQueue();
sp<DummyConsumer> dc(new DummyConsumer);
mConsumer->consumerConnect(dc, false);
@@ -139,6 +203,7 @@
}
TEST_F(BufferQueueTest, DetachAndReattachOnProducerSide) {
+ createBufferQueue();
sp<DummyConsumer> dc(new DummyConsumer);
ASSERT_EQ(OK, mConsumer->consumerConnect(dc, false));
IGraphicBufferProducer::QueueBufferOutput output;
@@ -187,9 +252,11 @@
ASSERT_EQ(OK, item.mGraphicBuffer->lock(GraphicBuffer::USAGE_SW_READ_OFTEN,
reinterpret_cast<void**>(&dataOut)));
ASSERT_EQ(*dataOut, 0x12345678);
+ ASSERT_EQ(OK, item.mGraphicBuffer->unlock());
}
TEST_F(BufferQueueTest, DetachAndReattachOnConsumerSide) {
+ createBufferQueue();
sp<DummyConsumer> dc(new DummyConsumer);
ASSERT_EQ(OK, mConsumer->consumerConnect(dc, false));
IGraphicBufferProducer::QueueBufferOutput output;
@@ -243,9 +310,11 @@
ASSERT_EQ(OK, buffer->lock(GraphicBuffer::USAGE_SW_READ_OFTEN,
reinterpret_cast<void**>(&dataOut)));
ASSERT_EQ(*dataOut, 0x12345678);
+ ASSERT_EQ(OK, buffer->unlock());
}
TEST_F(BufferQueueTest, MoveFromConsumerToProducer) {
+ createBufferQueue();
sp<DummyConsumer> dc(new DummyConsumer);
ASSERT_EQ(OK, mConsumer->consumerConnect(dc, false));
IGraphicBufferProducer::QueueBufferOutput output;
@@ -283,6 +352,7 @@
ASSERT_EQ(OK, item.mGraphicBuffer->lock(GraphicBuffer::USAGE_SW_READ_OFTEN,
reinterpret_cast<void**>(&dataOut)));
ASSERT_EQ(*dataOut, 0x12345678);
+ ASSERT_EQ(OK, item.mGraphicBuffer->unlock());
}
} // namespace android
diff --git a/opengl/tests/lib/WindowSurface.cpp b/opengl/tests/lib/WindowSurface.cpp
index ff91260..1428945 100644
--- a/opengl/tests/lib/WindowSurface.cpp
+++ b/opengl/tests/lib/WindowSurface.cpp
@@ -56,7 +56,7 @@
sp<SurfaceControl> sc = surfaceComposerClient->createSurface(
String8("Benchmark"), width, height,
- PIXEL_FORMAT_RGBA_8888, ISurfaceComposerClient::eOpaque);
+ PIXEL_FORMAT_RGBX_8888, ISurfaceComposerClient::eOpaque);
if (sc == NULL || !sc->isValid()) {
fprintf(stderr, "Failed to create SurfaceControl\n");
return;
diff --git a/services/inputflinger/EventHub.cpp b/services/inputflinger/EventHub.cpp
index 94fc0af..b70ea76 100644
--- a/services/inputflinger/EventHub.cpp
+++ b/services/inputflinger/EventHub.cpp
@@ -813,7 +813,7 @@
if (readSize == 0 || (readSize < 0 && errno == ENODEV)) {
// Device was removed before INotify noticed.
ALOGW("could not get event, removed? (fd: %d size: %d bufferSize: %d "
- "capacity: %d errno: %d)\n",
+ "capacity: %zu errno: %d)\n",
device->fd, readSize, bufferSize, capacity, errno);
deviceChanged = true;
closeDeviceLocked(device);
diff --git a/services/inputflinger/InputDispatcher.cpp b/services/inputflinger/InputDispatcher.cpp
index 95eee06..dbfc957 100644
--- a/services/inputflinger/InputDispatcher.cpp
+++ b/services/inputflinger/InputDispatcher.cpp
@@ -148,7 +148,7 @@
return false;
}
if (pointerCount < 1 || pointerCount > MAX_POINTERS) {
- ALOGE("Motion event has invalid pointer count %d; value must be between 1 and %d.",
+ ALOGE("Motion event has invalid pointer count %zu; value must be between 1 and %d.",
pointerCount, MAX_POINTERS);
return false;
}
diff --git a/services/inputflinger/InputReader.cpp b/services/inputflinger/InputReader.cpp
index 66f907a..f27ba96 100644
--- a/services/inputflinger/InputReader.cpp
+++ b/services/inputflinger/InputReader.cpp
@@ -6174,8 +6174,8 @@
&& mRawPointerAxes.slot.minValue == 0 && mRawPointerAxes.slot.maxValue > 0) {
size_t slotCount = mRawPointerAxes.slot.maxValue + 1;
if (slotCount > MAX_SLOTS) {
- ALOGW("MultiTouch Device %s reported %d slots but the framework "
- "only supports a maximum of %d slots at this time.",
+ ALOGW("MultiTouch Device %s reported %zu slots but the framework "
+ "only supports a maximum of %zu slots at this time.",
getDeviceName().string(), slotCount, MAX_SLOTS);
slotCount = MAX_SLOTS;
}
@@ -6347,7 +6347,7 @@
// If there are too many axes, start dropping them.
// Prefer to keep explicitly mapped axes.
if (mAxes.size() > PointerCoords::MAX_AXES) {
- ALOGI("Joystick '%s' has %d axes but the framework only supports a maximum of %d.",
+ ALOGI("Joystick '%s' has %zu axes but the framework only supports a maximum of %d.",
getDeviceName().string(), mAxes.size(), PointerCoords::MAX_AXES);
pruneAxes(true);
pruneAxes(false);
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 0650d97..d084bf5 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -2687,7 +2687,7 @@
looper->sendMessage(this, Message(MSG_API_CALL));
barrier.wait();
}
- return NO_ERROR;
+ return result;
}
/*
@@ -2697,7 +2697,7 @@
virtual void handleMessage(const Message& message) {
android_atomic_release_load(&memoryBarrier);
if (message.what == MSG_API_CALL) {
- impl->asBinder()->transact(code, data[0], reply);
+ result = impl->asBinder()->transact(code, data[0], reply);
barrier.open();
} else if (message.what == MSG_EXIT) {
exitRequested = true;