1 /*
2  * Copyright (C) 2015 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #define LOG_TAG "VehicleNetwork"
18 
19 #include <memory>
20 
21 #include <binder/IPCThreadState.h>
22 #include <private/android_filesystem_config.h>
23 
24 #include <utils/Log.h>
25 
26 #include <IVehicleNetwork.h>
27 #include <IVehicleNetworkHalMock.h>
28 #include <VehicleNetworkProto.pb.h>
29 
30 #include "BinderUtil.h"
31 #include "VehicleNetworkProtoUtil.h"
32 
33 namespace android {
34 
35 enum {
36     ON_LIST_PROPERTIES = IBinder::FIRST_CALL_TRANSACTION,
37     ON_PROPERTY_SET,
38     ON_PROPERTY_GET,
39     ON_SUBSCRIBE,
40     ON_UNSUBSCRIBE,
41 };
42 
43 // ----------------------------------------------------------------------------
44 
45 const char IVehicleNetworkHalMock::SERVICE_NAME[] =
46         "com.android.car.vehiclenetwork.IVehicleNetworkHalMock";
47 
48 // ----------------------------------------------------------------------------
49 
50 class BpVehicleNetworkHalMock : public BpInterface<IVehicleNetworkHalMock> {
51 public:
BpVehicleNetworkHalMock(const sp<IBinder> & impl)52     BpVehicleNetworkHalMock(const sp<IBinder> & impl)
53         : BpInterface<IVehicleNetworkHalMock>(impl) {
54     }
55 
onListProperties()56     virtual sp<VehiclePropertiesHolder> onListProperties() {
57         sp<VehiclePropertiesHolder> holder;
58         Parcel data, reply;
59         data.writeInterfaceToken(IVehicleNetworkHalMock::getInterfaceDescriptor());
60         status_t status = remote()->transact(ON_LIST_PROPERTIES, data, &reply);
61         if (status == NO_ERROR) {
62             reply.readExceptionCode(); // for compatibility with java
63             if (reply.readInt32() == 0) { // no result
64                 return holder;
65             }
66             ReadableBlobHolder blob(new Parcel::ReadableBlob());
67             if (blob.blob == NULL) {
68                 ALOGE("listProperties, no memory");
69                 return holder;
70             }
71             int32_t size = reply.readInt32();
72             status = reply.readBlob(size, blob.blob);
73             if (status != NO_ERROR) {
74                 ALOGE("listProperties, cannot read blob %d", status);
75                 return holder;
76             }
77             //TODO make this more memory efficient
78             std::unique_ptr<VehiclePropConfigs> configs(new VehiclePropConfigs());
79             if (configs.get() == NULL) {
80                 return holder;
81             }
82             if(!configs->ParseFromArray(blob.blob->data(), size)) {
83                 ALOGE("listProperties, cannot parse reply");
84                 return holder;
85             }
86             holder = new VehiclePropertiesHolder();
87             ASSERT_OR_HANDLE_NO_MEMORY(holder.get(), return);
88             status = VehicleNetworkProtoUtil::fromVehiclePropConfigs(*configs.get(),
89                     holder->getList());
90             if (status != NO_ERROR) {
91                 ALOGE("listProperties, cannot convert VehiclePropConfigs %d", status);
92                 return holder;
93             }
94 
95         }
96         return holder;
97     }
98 
onPropertySet(const vehicle_prop_value_t & value)99     virtual status_t onPropertySet(const vehicle_prop_value_t& value) {
100         Parcel data, reply;
101         data.writeInterfaceToken(IVehicleNetworkHalMock::getInterfaceDescriptor());
102         status_t status = VehiclePropValueBinderUtil::writeToParcel(data, value);
103         if (status != NO_ERROR) {
104             return status;
105         }
106         status = remote()->transact(ON_PROPERTY_SET, data, &reply);
107         return status;
108     }
109 
onPropertyGet(vehicle_prop_value_t * value)110     virtual status_t onPropertyGet(vehicle_prop_value_t* value) {
111         if (value == NULL) {
112             return BAD_VALUE;
113         }
114         Parcel data, reply;
115         data.writeInterfaceToken(IVehicleNetworkHalMock::getInterfaceDescriptor());
116         status_t status = VehiclePropValueBinderUtil::writeToParcel(data, *value);
117         if (status != NO_ERROR) {
118             return status;
119         }
120         status = remote()->transact(ON_PROPERTY_GET, data, &reply);
121         if (status == NO_ERROR) {
122             reply.readExceptionCode(); // for compatibility with java
123             status = VehiclePropValueBinderUtil::readFromParcel(reply, value);
124         }
125         return status;
126     }
127 
onPropertySubscribe(int32_t property,float sampleRate,int32_t zones)128     virtual status_t onPropertySubscribe(int32_t property, float sampleRate, int32_t zones) {
129         Parcel data, reply;
130         data.writeInterfaceToken(IVehicleNetworkHalMock::getInterfaceDescriptor());
131         data.writeInt32(property);
132         data.writeFloat(sampleRate);
133         data.writeInt32(zones);
134         status_t status = remote()->transact(ON_SUBSCRIBE, data, &reply);
135         return status;
136     }
137 
onPropertyUnsubscribe(int32_t property)138     virtual void onPropertyUnsubscribe(int32_t property) {
139         Parcel data, reply;
140         data.writeInterfaceToken(IVehicleNetworkHalMock::getInterfaceDescriptor());
141         data.writeInt32(property);
142         status_t status = remote()->transact(ON_UNSUBSCRIBE, data, &reply);
143         if (status != NO_ERROR) {
144             ALOGI("onPropertyUnsubscribe property %d failed %d", property, status);
145         }
146     }
147 };
148 
149 IMPLEMENT_META_INTERFACE(VehicleNetworkHalMock, IVehicleNetworkHalMock::SERVICE_NAME);
150 
151 // ----------------------------------------------------------------------
152 
isSystemUser()153 static bool isSystemUser() {
154     uid_t uid =  IPCThreadState::self()->getCallingUid();
155     switch (uid) {
156         // This list will be expanded. Only those UIDs are allowed to access vehicle network
157         // for now. There can be per property based UID check built-in as well.
158         case AID_ROOT:
159         case AID_SYSTEM:
160         case AID_AUDIO: {
161             return true;
162         } break;
163         default: {
164             ALOGE("non-system user tried access, uid %d", uid);
165         } break;
166     }
167     return false;
168 }
169 
onTransact(uint32_t code,const Parcel & data,Parcel * reply,uint32_t flags)170 status_t BnVehicleNetworkHalMock::onTransact(uint32_t code, const Parcel& data, Parcel* reply,
171         uint32_t flags) {
172     if (!isSystemUser()) {
173         return PERMISSION_DENIED;
174     }
175     status_t r;
176     switch (code) {
177         case ON_LIST_PROPERTIES: {
178             CHECK_INTERFACE(IVehicleNetworkHalMock, data, reply);
179             sp<VehiclePropertiesHolder> holder = onListProperties();
180             if (holder.get() == NULL) { // given property not found
181                 BinderUtil::fillObjectResultReply(reply, false /* isValid */);
182                 return NO_ERROR;
183             }
184             std::unique_ptr<VehiclePropConfigs> configs(new VehiclePropConfigs());
185             ASSERT_OR_HANDLE_NO_MEMORY(configs.get(), return NO_MEMORY);
186             VehicleNetworkProtoUtil::toVehiclePropConfigs(holder->getList(), *configs.get());
187             int size = configs->ByteSize();
188             WritableBlobHolder blob(new Parcel::WritableBlob());
189             ASSERT_OR_HANDLE_NO_MEMORY(blob.blob, return NO_MEMORY);
190             BinderUtil::fillObjectResultReply(reply, true);
191             reply->writeInt32(size);
192             reply->writeBlob(size, false, blob.blob);
193             configs->SerializeToArray(blob.blob->data(), size);
194             return NO_ERROR;
195         } break;
196         case ON_PROPERTY_SET: {
197             CHECK_INTERFACE(IVehicleNetworkHalMock, data, reply);
198             if (data.readInt32() == 0) { // java side allows passing null with this.
199                 return BAD_VALUE;
200             }
201             ScopedVehiclePropValue value;
202             ReadableBlobHolder blob(new Parcel::ReadableBlob());
203             ASSERT_OR_HANDLE_NO_MEMORY(blob.blob, return NO_MEMORY);
204             int32_t size = data.readInt32();
205             r = data.readBlob(size, blob.blob);
206             if (r != NO_ERROR) {
207                 ALOGE("setProperty:service, cannot read blob");
208                 return r;
209             }
210             std::unique_ptr<VehiclePropValue> v(new VehiclePropValue());
211             ASSERT_OR_HANDLE_NO_MEMORY(v.get(), return NO_MEMORY);
212             if (!v->ParseFromArray(blob.blob->data(), size)) {
213                 ALOGE("setProperty:service, cannot parse data");
214                 return BAD_VALUE;
215             }
216             r = VehicleNetworkProtoUtil::fromVehiclePropValue(*v.get(), value.value);
217             if (r != NO_ERROR) {
218                 ALOGE("setProperty:service, cannot convert data");
219                 return BAD_VALUE;
220             }
221             r = onPropertySet(value.value);
222             BinderUtil::fillNoResultReply(reply);
223             return r;
224         } break;
225         case ON_PROPERTY_GET: {
226             CHECK_INTERFACE(IVehicleNetworkHalMock, data, reply);
227             ScopedVehiclePropValue value;
228             r = VehiclePropValueBinderUtil::readFromParcel(data, &value.value,
229                                 false /* deleteMembers */, true /*canIgnoreNoData*/);
230             if (r != NO_ERROR) {
231                 ALOGE("onPropertyGet cannot read %d", r);
232                 return r;
233             }
234             r = onPropertyGet(&(value.value));
235             if (r == NO_ERROR) {
236                 BinderUtil::fillObjectResultReply(reply, true);
237                 std::unique_ptr<VehiclePropValue> v(new VehiclePropValue());
238                 ASSERT_OR_HANDLE_NO_MEMORY(v.get(), return NO_MEMORY);
239                 VehicleNetworkProtoUtil::toVehiclePropValue(value.value, *v.get());
240                 int size = v->ByteSize();
241                 WritableBlobHolder blob(new Parcel::WritableBlob());
242                 ASSERT_OR_HANDLE_NO_MEMORY(blob.blob, return NO_MEMORY);
243                 reply->writeInt32(size);
244                 reply->writeBlob(size, false, blob.blob);
245                 v->SerializeToArray(blob.blob->data(), size);
246             }
247             return r;
248         } break;
249         case ON_SUBSCRIBE: {
250             CHECK_INTERFACE(IVehicleNetworkHalMock, data, reply);
251             int32_t property = data.readInt32();
252             float sampleRate = data.readFloat();
253             int32_t zones = data.readInt32();
254             r = onPropertySubscribe(property, sampleRate, zones);
255             BinderUtil::fillNoResultReply(reply);
256             return r;
257         } break;
258         case ON_UNSUBSCRIBE: {
259             CHECK_INTERFACE(IVehicleNetworkHalMock, data, reply);
260             int32_t property = data.readInt32();
261             onPropertyUnsubscribe(property);
262             BinderUtil::fillNoResultReply(reply);
263             return NO_ERROR;
264         } break;
265         default:
266             return BBinder::onTransact(code, data, reply, flags);
267     }
268 }
269 
270 }; // namespace android
271