blob: 37c4f27cc0a3ab9d09714b796a079093840c3a24 [file] [log] [blame]
// 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 <ditto/binder.h>
#include <ditto/binder_request.h>
#include <ditto/logger.h>
#include <cutils/ashmem.h>
#include <sys/mman.h>
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<IDittoBinder>(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<android::IMountService>(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
<dittosuiteproto::BinderRequest_GenericService_ParcelInput> parcel_input)
: BinderRequest(kName, params, service_name), parcel_input_(parcel_input),
service_name_(service_name), code_(code) {}
void GenericBinderRequest::SetUp() {
android::sp<android::IServiceManager> 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
<dittosuiteproto::BinderRequest_GenericService_ParcelInput>& 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