Add C++ implementation of ParcelFileDescriptor
Bug: 80377815
Test: make binderLibTest && adb sync && adb shell /data/nativetest64/binderLibTest/binderLibTest
Change-Id: I1c54a80b7bf1cf1a51987502e4d844765c20531d
diff --git a/libs/binder/Android.bp b/libs/binder/Android.bp
index d4db8c8..715c1c1 100644
--- a/libs/binder/Android.bp
+++ b/libs/binder/Android.bp
@@ -61,6 +61,7 @@
"MemoryDealer.cpp",
"MemoryHeapBase.cpp",
"Parcel.cpp",
+ "ParcelFileDescriptor.cpp",
"PermissionCache.cpp",
"PersistableBundle.cpp",
"ProcessInfoService.cpp",
diff --git a/libs/binder/Parcel.cpp b/libs/binder/Parcel.cpp
index f739f07..e221c6d 100644
--- a/libs/binder/Parcel.cpp
+++ b/libs/binder/Parcel.cpp
@@ -1179,6 +1179,19 @@
return writeFileDescriptor(fd, takeOwnership);
}
+status_t Parcel::writeDupParcelFileDescriptor(int fd)
+{
+ int dupFd = fcntl(fd, F_DUPFD_CLOEXEC, 0);
+ if (dupFd < 0) {
+ return -errno;
+ }
+ status_t err = writeParcelFileDescriptor(dupFd, true /*takeOwnership*/);
+ if (err != OK) {
+ close(dupFd);
+ }
+ return err;
+}
+
status_t Parcel::writeUniqueFileDescriptor(const base::unique_fd& fd) {
return writeDupFileDescriptor(fd.get());
}
@@ -2167,6 +2180,22 @@
return OK;
}
+status_t Parcel::readUniqueParcelFileDescriptor(base::unique_fd* val) const
+{
+ int got = readParcelFileDescriptor();
+
+ if (got == BAD_TYPE) {
+ return BAD_TYPE;
+ }
+
+ val->reset(fcntl(got, F_DUPFD_CLOEXEC, 0));
+
+ if (val->get() < 0) {
+ return BAD_VALUE;
+ }
+
+ return OK;
+}
status_t Parcel::readUniqueFileDescriptorVector(std::unique_ptr<std::vector<base::unique_fd>>* val) const {
return readNullableTypedVector(val, &Parcel::readUniqueFileDescriptor);
diff --git a/libs/binder/ParcelFileDescriptor.cpp b/libs/binder/ParcelFileDescriptor.cpp
new file mode 100644
index 0000000..4f8b76f
--- /dev/null
+++ b/libs/binder/ParcelFileDescriptor.cpp
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <binder/ParcelFileDescriptor.h>
+
+namespace android {
+namespace os {
+
+ParcelFileDescriptor::ParcelFileDescriptor() = default;
+
+ParcelFileDescriptor::ParcelFileDescriptor(android::base::unique_fd fd) : mFd(std::move(fd)) {}
+
+ParcelFileDescriptor::~ParcelFileDescriptor() = default;
+
+status_t ParcelFileDescriptor::writeToParcel(Parcel* parcel) const {
+ return parcel->writeDupParcelFileDescriptor(mFd.get());
+}
+
+status_t ParcelFileDescriptor::readFromParcel(const Parcel* parcel) {
+ return parcel->readUniqueParcelFileDescriptor(&mFd);
+}
+
+} // namespace os
+} // namespace android
diff --git a/libs/binder/include/binder/Parcel.h b/libs/binder/include/binder/Parcel.h
index 5d36526..b9a3ae6 100644
--- a/libs/binder/include/binder/Parcel.h
+++ b/libs/binder/include/binder/Parcel.h
@@ -205,6 +205,10 @@
// The Parcel does not take ownership of the given fd unless you ask it to.
status_t writeParcelFileDescriptor(int fd, bool takeOwnership = false);
+ // Place a Java "parcel file descriptor" into the parcel. A dup of the fd is made, which will
+ // be closed once the parcel is destroyed.
+ status_t writeDupParcelFileDescriptor(int fd);
+
// Place a file descriptor into the parcel. This will not affect the
// semantics of the smart file descriptor. A new descriptor will be
// created, and will be closed when the parcel is destroyed.
@@ -364,6 +368,9 @@
status_t readUniqueFileDescriptor(
base::unique_fd* val) const;
+ // Retrieve a Java "parcel file descriptor" from the parcel.
+ status_t readUniqueParcelFileDescriptor(base::unique_fd* val) const;
+
// Retrieve a vector of smart file descriptors from the parcel.
status_t readUniqueFileDescriptorVector(
diff --git a/libs/binder/include/binder/ParcelFileDescriptor.h b/libs/binder/include/binder/ParcelFileDescriptor.h
new file mode 100644
index 0000000..455462b
--- /dev/null
+++ b/libs/binder/include/binder/ParcelFileDescriptor.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_PARCEL_FILE_DESCRIPTOR_H_
+#define ANDROID_PARCEL_FILE_DESCRIPTOR_H_
+
+#include <android-base/unique_fd.h>
+#include <binder/Parcel.h>
+#include <binder/Parcelable.h>
+
+namespace android {
+namespace os {
+
+/*
+ * C++ implementation of the Java class android.os.ParcelFileDescriptor
+ */
+class ParcelFileDescriptor : public android::Parcelable {
+public:
+ ParcelFileDescriptor();
+ explicit ParcelFileDescriptor(android::base::unique_fd fd);
+ ~ParcelFileDescriptor() override;
+
+ int get() const { return mFd.get(); }
+ android::base::unique_fd release() { return std::move(mFd); }
+ void reset(android::base::unique_fd fd = android::base::unique_fd()) { mFd = std::move(fd); }
+
+ // android::Parcelable override:
+ android::status_t writeToParcel(android::Parcel* parcel) const override;
+ android::status_t readFromParcel(const android::Parcel* parcel) override;
+
+private:
+ android::base::unique_fd mFd;
+};
+
+} // namespace os
+} // namespace android
+
+#endif // ANDROID_OS_PARCEL_FILE_DESCRIPTOR_H_
diff --git a/libs/binder/tests/binderLibTest.cpp b/libs/binder/tests/binderLibTest.cpp
index 1611e11..fb9b3fe 100644
--- a/libs/binder/tests/binderLibTest.cpp
+++ b/libs/binder/tests/binderLibTest.cpp
@@ -65,6 +65,7 @@
BINDER_LIB_TEST_ADD_STRONG_REF_TRANSACTION,
BINDER_LIB_TEST_LINK_DEATH_TRANSACTION,
BINDER_LIB_TEST_WRITE_FILE_TRANSACTION,
+ BINDER_LIB_TEST_WRITE_PARCEL_FILE_DESCRIPTOR_TRANSACTION,
BINDER_LIB_TEST_PROMOTE_WEAK_REF_TRANSACTION,
BINDER_LIB_TEST_EXIT_TRANSACTION,
BINDER_LIB_TEST_DELAYED_EXIT_TRANSACTION,
@@ -763,6 +764,41 @@
close(pipefd[0]);
}
+TEST_F(BinderLibTest, PassParcelFileDescriptor) {
+ const int datasize = 123;
+ std::vector<uint8_t> writebuf(datasize);
+ for (size_t i = 0; i < writebuf.size(); ++i) {
+ writebuf[i] = i;
+ }
+
+ android::base::unique_fd read_end, write_end;
+ {
+ int pipefd[2];
+ ASSERT_EQ(0, pipe2(pipefd, O_NONBLOCK));
+ read_end.reset(pipefd[0]);
+ write_end.reset(pipefd[1]);
+ }
+ {
+ Parcel data;
+ EXPECT_EQ(NO_ERROR, data.writeDupParcelFileDescriptor(write_end.get()));
+ write_end.reset();
+ EXPECT_EQ(NO_ERROR, data.writeInt32(datasize));
+ EXPECT_EQ(NO_ERROR, data.write(writebuf.data(), datasize));
+
+ Parcel reply;
+ EXPECT_EQ(NO_ERROR,
+ m_server->transact(BINDER_LIB_TEST_WRITE_PARCEL_FILE_DESCRIPTOR_TRANSACTION, data,
+ &reply));
+ }
+ std::vector<uint8_t> readbuf(datasize);
+ EXPECT_EQ(datasize, read(read_end.get(), readbuf.data(), datasize));
+ EXPECT_EQ(writebuf, readbuf);
+
+ waitForReadData(read_end.get(), 5000); /* wait for other proccess to close pipe */
+
+ EXPECT_EQ(0, read(read_end.get(), readbuf.data(), datasize));
+}
+
TEST_F(BinderLibTest, PromoteLocal) {
sp<IBinder> strong = new BBinder();
wp<IBinder> weak = strong;
@@ -1138,6 +1174,28 @@
return UNKNOWN_ERROR;
return NO_ERROR;
}
+ case BINDER_LIB_TEST_WRITE_PARCEL_FILE_DESCRIPTOR_TRANSACTION: {
+ int ret;
+ int32_t size;
+ const void *buf;
+ android::base::unique_fd fd;
+
+ ret = data.readUniqueParcelFileDescriptor(&fd);
+ if (ret != NO_ERROR) {
+ return ret;
+ }
+ ret = data.readInt32(&size);
+ if (ret != NO_ERROR) {
+ return ret;
+ }
+ buf = data.readInplace(size);
+ if (buf == NULL) {
+ return BAD_VALUE;
+ }
+ ret = write(fd.get(), buf, size);
+ if (ret != size) return UNKNOWN_ERROR;
+ return NO_ERROR;
+ }
case BINDER_LIB_TEST_PROMOTE_WEAK_REF_TRANSACTION: {
int ret;
wp<IBinder> weak;
@@ -1300,4 +1358,3 @@
ProcessState::self()->startThreadPool();
return RUN_ALL_TESTS();
}
-