diff options
| author | 2018-05-31 16:58:35 +0900 | |
|---|---|---|
| committer | 2018-05-31 17:01:57 +0900 | |
| commit | bf5518938b7462fed0bf60d1fdfae58afb32b6ea (patch) | |
| tree | 00c32650280e855f4460743b1aabbcb67488a37c | |
| parent | 14906cd8e9e627c9ab8f3e9ad549812f41ffa630 (diff) | |
Add C++ implementation of ParcelFileDescriptor
Bug: 80377815
Test: make binderLibTest && adb sync && adb shell /data/nativetest64/binderLibTest/binderLibTest
Change-Id: I1c54a80b7bf1cf1a51987502e4d844765c20531d
| -rw-r--r-- | libs/binder/Android.bp | 1 | ||||
| -rw-r--r-- | libs/binder/Parcel.cpp | 29 | ||||
| -rw-r--r-- | libs/binder/ParcelFileDescriptor.cpp | 37 | ||||
| -rw-r--r-- | libs/binder/include/binder/Parcel.h | 7 | ||||
| -rw-r--r-- | libs/binder/include/binder/ParcelFileDescriptor.h | 51 | ||||
| -rw-r--r-- | libs/binder/tests/binderLibTest.cpp | 59 |
6 files changed, 183 insertions, 1 deletions
diff --git a/libs/binder/Android.bp b/libs/binder/Android.bp index d4db8c81b4..715c1c1dca 100644 --- a/libs/binder/Android.bp +++ b/libs/binder/Android.bp @@ -61,6 +61,7 @@ cc_library { "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 f739f07024..e221c6d6ff 100644 --- a/libs/binder/Parcel.cpp +++ b/libs/binder/Parcel.cpp @@ -1179,6 +1179,19 @@ status_t Parcel::writeParcelFileDescriptor(int fd, bool takeOwnership) 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 @@ status_t Parcel::readUniqueFileDescriptor(base::unique_fd* val) const 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 0000000000..4f8b76f7d9 --- /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 5d36526cb3..b9a3ae6cec 100644 --- a/libs/binder/include/binder/Parcel.h +++ b/libs/binder/include/binder/Parcel.h @@ -205,6 +205,10 @@ public: // 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 @@ public: 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 0000000000..455462b18f --- /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 1611e11209..fb9b3fe8d6 100644 --- a/libs/binder/tests/binderLibTest.cpp +++ b/libs/binder/tests/binderLibTest.cpp @@ -65,6 +65,7 @@ enum BinderLibTestTranscationCode { 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 @@ TEST_F(BinderLibTest, PassFile) { 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 @@ class BinderLibTestService : public BBinder 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 @@ int main(int argc, char **argv) { ProcessState::self()->startThreadPool(); return RUN_ALL_TESTS(); } - |