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