1 // Copyright (C) 2023 The Android Open Source Project
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 #if __ANDROID__
16
17 #include <ditto/binder.h>
18 #include <ditto/binder_request.h>
19 #include <ditto/logger.h>
20 #include <cutils/ashmem.h>
21 #include <sys/mman.h>
22
23
24 namespace dittosuite {
25
BinderRequest(const std::string & kName,const Params & params,const std::string & service_name)26 BinderRequest::BinderRequest(const std::string& kName, const Params& params,
27 const std::string& service_name)
28 : Instruction(kName, params), service_name_(service_name) {}
29
BinderRequestDitto(const Params & params,const std::string & service_name)30 BinderRequestDitto::BinderRequestDitto(const Params& params, const std::string& service_name)
31 : BinderRequest(kName, params, service_name) {}
32
RunSingle()33 void BinderRequestDitto::RunSingle() {
34 const int8_t c = 1;
35
36 int8_t ret = service_->sync(c);
37 if (ret != (~c)) {
38 LOGF("Wrong result, expected: " + std::to_string(~c) + ", but got: " + std::to_string(ret));
39 }
40 LOGD("Returned from Binder request: " + std::to_string(ret));
41 }
42
SetUp()43 void BinderRequestDitto::SetUp() {
44 LOGD("Starting binder requester for service: " + service_name_);
45 service_ = getBinderService<IDittoBinder>(service_name_);
46 service_->start();
47 Instruction::SetUp();
48 }
49
TearDownSingle(bool is_last)50 void BinderRequestDitto::TearDownSingle(bool is_last) {
51 Instruction::TearDownSingle(is_last);
52 if (is_last) {
53 LOGD("This is the last, sending termination request");
54 service_->end();
55 }
56 }
57
BinderRequestMountService(const Params & params)58 BinderRequestMountService::BinderRequestMountService(const Params& params)
59 : BinderRequest(kName, params, "mount") {}
60
RunSingle()61 void BinderRequestMountService::RunSingle() {
62 bool ret = service_->isUsbMassStorageConnected();
63 LOGD("Returned from Binder request: " + std::to_string(ret));
64 }
65
SetUp()66 void BinderRequestMountService::SetUp() {
67 LOGD("Starting binder requester for service: " + service_name_);
68 service_ = getBinderService<android::IMountService>(service_name_);
69 Instruction::SetUp();
70 }
71
TearDownSingle(bool last)72 void BinderRequestMountService::TearDownSingle(bool last) {
73 Instruction::TearDownSingle(last);
74 }
75
GenericBinderRequest(const Params & params,std::string service_name,int32_t code,const google::protobuf::RepeatedPtrField<dittosuiteproto::BinderRequest_GenericService_ParcelInput> parcel_input)76 GenericBinderRequest::GenericBinderRequest(const Params& params,
77 std::string service_name, int32_t code,
78 const google::protobuf::RepeatedPtrField
79 <dittosuiteproto::BinderRequest_GenericService_ParcelInput> parcel_input)
80 : BinderRequest(kName, params, service_name), parcel_input_(parcel_input),
81 service_name_(service_name), code_(code) {}
82
SetUp()83 void GenericBinderRequest::SetUp() {
84 android::sp<android::IServiceManager> sm = android::defaultServiceManager();
85 service_ = sm->checkService(String16(service_name_.c_str(), service_name_.length()));
86 }
87
TearDownSingle(bool last)88 void GenericBinderRequest::TearDownSingle(bool last) {
89 Instruction::TearDownSingle(last);
90 }
91
ParseAshmemWithPath(std::string path,android::Parcel & parcel)92 int ParseAshmemWithPath(std::string path, android::Parcel& parcel) {
93 int fd = open(path.c_str(), O_RDONLY);
94 struct stat statbuf;
95 int afd = -1;
96 void* ptr = MAP_FAILED;
97 if (fd < 0) {
98 LOGF("Could not open " + path);
99 return -1;
100 }
101 if (fstat(fd, &statbuf) != 0) {
102 LOGF("Could not stat " + path);
103 goto error_close_fd;
104 }
105 afd = ashmem_create_region("ditto", statbuf.st_size);
106 if (afd < 0) {
107 LOGF("ashmem_create_region failed " + path);
108 goto error_close_fd;
109 }
110 ptr = mmap(NULL, statbuf.st_size, PROT_READ | PROT_WRITE, MAP_SHARED, afd, 0);
111 if (ptr == MAP_FAILED) {
112 LOGF("mmap failed " + path);
113 goto error_close_afd;
114 }
115 if (read(fd, ptr, statbuf.st_size) < 0) {
116 LOGF("read failed " + path);
117 goto error_unmap;
118 }
119 if (parcel.writeFileDescriptor(afd, true /* take ownership */) == android::OK) {
120 // successfully parsed. unmap and afd close is done by the binder server.
121 close(fd);
122 return 0;
123 }
124 LOGF("writeFileDescriptor failed " + path);
125
126 error_unmap:
127 munmap(ptr, statbuf.st_size);
128 error_close_afd:
129 close(afd);
130 error_close_fd:
131 close(fd);
132 return -1;
133 }
134
ParseParcelString(const google::protobuf::RepeatedPtrField<dittosuiteproto::BinderRequest_GenericService_ParcelInput> & input,android::Parcel & parcel)135 int ParseParcelString(const google::protobuf::RepeatedPtrField
136 <dittosuiteproto::BinderRequest_GenericService_ParcelInput>& input,
137 android::Parcel& parcel) {
138 for (const auto &it : input ) {
139 std::string data_str = it.data();
140 switch (it.type()) {
141 case dittosuiteproto::BinderRequest_GenericService_ParcelInput_Type_I32: {
142 parcel.writeInt32(atoi(data_str.c_str()));
143 break;
144 }
145 case dittosuiteproto::BinderRequest_GenericService_ParcelInput_Type_I64: {
146 parcel.writeInt64(atoll(data_str.c_str()));
147 break;
148 }
149 case dittosuiteproto::BinderRequest_GenericService_ParcelInput_Type_STRING_16: {
150 parcel.writeString16(String16(data_str.c_str(), data_str.length()));
151 break;
152 }
153 case dittosuiteproto::BinderRequest_GenericService_ParcelInput_Type_F: {
154 parcel.writeFloat(atof(data_str.c_str()));
155 break;
156 }
157 case dittosuiteproto::BinderRequest_GenericService_ParcelInput_Type_D: {
158 parcel.writeDouble(atof(data_str.c_str()));
159 break;
160 }
161 case dittosuiteproto::BinderRequest_GenericService_ParcelInput_Type_NULL_: {
162 parcel.writeStrongBinder(nullptr);
163 break;
164 }
165 case dittosuiteproto::BinderRequest_GenericService_ParcelInput_Type_FD: {
166 parcel.writeFileDescriptor(atoi(data_str.c_str()), true /* take ownership */);
167 break;
168 }
169 case dittosuiteproto::BinderRequest_GenericService_ParcelInput_Type_FD_PATH: {
170 int fd = open(data_str.c_str(), O_RDONLY);
171 if (fd < 0) {
172 LOGF("Could not open " + data_str);
173 return -1;
174 }
175 parcel.writeFileDescriptor(fd, true /* take ownership */);
176 break;
177 }
178 case dittosuiteproto::BinderRequest_GenericService_ParcelInput_Type_ASHMEM_FD_PATH: {
179 if (ParseAshmemWithPath(data_str.c_str(), parcel) < 0) {
180 return -1;
181 }
182 break;
183 }
184 case dittosuiteproto::BinderRequest_GenericService_ParcelInput_Type_PARCEL: {
185 int res = 0;
186 auto inputs = it.nested_parcel().parcel_inputs();
187 if (inputs.size() == 0) {
188 // Null parcelable flag.
189 res = parcel.writeInt32(0);
190 } else {
191 // Non-Null parcelable flag.
192 res = parcel.writeInt32(1);
193 if (res < 0) return res;
194 res = ParseParcelString(it.nested_parcel().parcel_inputs(), parcel);
195 }
196 if (res < 0) {
197 return res;
198 }
199 break;
200 }
201 default:
202 break;
203 }
204 }
205 return 0;
206 }
207
RunSingle()208 void GenericBinderRequest::RunSingle() {
209 android::Parcel data, reply;
210 data.markForBinder(service_);
211 data.writeInterfaceToken(service_ ? service_->getInterfaceDescriptor() : String16());
212 if (ParseParcelString(parcel_input_, data)) {
213 LOGF("Error parsing parcel string\n");
214 return;
215 }
216
217 service_->transact(code_, data, &reply);
218
219 std::stringstream ss;
220 ss << reply;
221 LOGD("Returned from Binder transact:\n" + ss.str());
222 }
223 } // namespace dittosuite
224
225 #endif
226