// Copyright (C) 2023 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. #if __ANDROID__ #include #include #include #include #include namespace dittosuite { BinderRequest::BinderRequest(const std::string& kName, const Params& params, const std::string& service_name) : Instruction(kName, params), service_name_(service_name) {} BinderRequestDitto::BinderRequestDitto(const Params& params, const std::string& service_name) : BinderRequest(kName, params, service_name) {} void BinderRequestDitto::RunSingle() { const int8_t c = 1; int8_t ret = service_->sync(c); if (ret != (~c)) { LOGF("Wrong result, expected: " + std::to_string(~c) + ", but got: " + std::to_string(ret)); } LOGD("Returned from Binder request: " + std::to_string(ret)); } void BinderRequestDitto::SetUp() { LOGD("Starting binder requester for service: " + service_name_); service_ = getBinderService(service_name_); service_->start(); Instruction::SetUp(); } void BinderRequestDitto::TearDownSingle(bool is_last) { Instruction::TearDownSingle(is_last); if (is_last) { LOGD("This is the last, sending termination request"); service_->end(); } } BinderRequestMountService::BinderRequestMountService(const Params& params) : BinderRequest(kName, params, "mount") {} void BinderRequestMountService::RunSingle() { bool ret = service_->isUsbMassStorageConnected(); LOGD("Returned from Binder request: " + std::to_string(ret)); } void BinderRequestMountService::SetUp() { LOGD("Starting binder requester for service: " + service_name_); service_ = getBinderService(service_name_); Instruction::SetUp(); } void BinderRequestMountService::TearDownSingle(bool last) { Instruction::TearDownSingle(last); } GenericBinderRequest::GenericBinderRequest(const Params& params, std::string service_name, int32_t code, const google::protobuf::RepeatedPtrField parcel_input) : BinderRequest(kName, params, service_name), parcel_input_(parcel_input), service_name_(service_name), code_(code) {} void GenericBinderRequest::SetUp() { android::sp sm = android::defaultServiceManager(); service_ = sm->checkService(String16(service_name_.c_str(), service_name_.length())); } void GenericBinderRequest::TearDownSingle(bool last) { Instruction::TearDownSingle(last); } int ParseAshmemWithPath(std::string path, android::Parcel& parcel) { int fd = open(path.c_str(), O_RDONLY); struct stat statbuf; int afd = -1; void* ptr = MAP_FAILED; if (fd < 0) { LOGF("Could not open " + path); return -1; } if (fstat(fd, &statbuf) != 0) { LOGF("Could not stat " + path); goto error_close_fd; } afd = ashmem_create_region("ditto", statbuf.st_size); if (afd < 0) { LOGF("ashmem_create_region failed " + path); goto error_close_fd; } ptr = mmap(NULL, statbuf.st_size, PROT_READ | PROT_WRITE, MAP_SHARED, afd, 0); if (ptr == MAP_FAILED) { LOGF("mmap failed " + path); goto error_close_afd; } if (read(fd, ptr, statbuf.st_size) < 0) { LOGF("read failed " + path); goto error_unmap; } if (parcel.writeFileDescriptor(afd, true /* take ownership */) == android::OK) { // successfully parsed. unmap and afd close is done by the binder server. close(fd); return 0; } LOGF("writeFileDescriptor failed " + path); error_unmap: munmap(ptr, statbuf.st_size); error_close_afd: close(afd); error_close_fd: close(fd); return -1; } int ParseParcelString(const google::protobuf::RepeatedPtrField & input, android::Parcel& parcel) { for (const auto &it : input ) { std::string data_str = it.data(); switch (it.type()) { case dittosuiteproto::BinderRequest_GenericService_ParcelInput_Type_I32: { parcel.writeInt32(atoi(data_str.c_str())); break; } case dittosuiteproto::BinderRequest_GenericService_ParcelInput_Type_I64: { parcel.writeInt64(atoll(data_str.c_str())); break; } case dittosuiteproto::BinderRequest_GenericService_ParcelInput_Type_STRING_16: { parcel.writeString16(String16(data_str.c_str(), data_str.length())); break; } case dittosuiteproto::BinderRequest_GenericService_ParcelInput_Type_F: { parcel.writeFloat(atof(data_str.c_str())); break; } case dittosuiteproto::BinderRequest_GenericService_ParcelInput_Type_D: { parcel.writeDouble(atof(data_str.c_str())); break; } case dittosuiteproto::BinderRequest_GenericService_ParcelInput_Type_NULL_: { parcel.writeStrongBinder(nullptr); break; } case dittosuiteproto::BinderRequest_GenericService_ParcelInput_Type_FD: { parcel.writeFileDescriptor(atoi(data_str.c_str()), true /* take ownership */); break; } case dittosuiteproto::BinderRequest_GenericService_ParcelInput_Type_FD_PATH: { int fd = open(data_str.c_str(), O_RDONLY); if (fd < 0) { LOGF("Could not open " + data_str); return -1; } parcel.writeFileDescriptor(fd, true /* take ownership */); break; } case dittosuiteproto::BinderRequest_GenericService_ParcelInput_Type_ASHMEM_FD_PATH: { if (ParseAshmemWithPath(data_str.c_str(), parcel) < 0) { return -1; } break; } case dittosuiteproto::BinderRequest_GenericService_ParcelInput_Type_PARCEL: { int res = 0; auto inputs = it.nested_parcel().parcel_inputs(); if (inputs.size() == 0) { // Null parcelable flag. res = parcel.writeInt32(0); } else { // Non-Null parcelable flag. res = parcel.writeInt32(1); if (res < 0) return res; res = ParseParcelString(it.nested_parcel().parcel_inputs(), parcel); } if (res < 0) { return res; } break; } default: break; } } return 0; } void GenericBinderRequest::RunSingle() { android::Parcel data, reply; data.markForBinder(service_); data.writeInterfaceToken(service_ ? service_->getInterfaceDescriptor() : String16()); if (ParseParcelString(parcel_input_, data)) { LOGF("Error parsing parcel string\n"); return; } service_->transact(code_, data, &reply); std::stringstream ss; ss << reply; LOGD("Returned from Binder transact:\n" + ss.str()); } } // namespace dittosuite #endif