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