/* * Copyright (C) 2015 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. */ #define LOG_TAG "VehicleNetwork" #include <memory> #include <binder/IPCThreadState.h> #include <private/android_filesystem_config.h> #include <utils/Log.h> #include <IVehicleNetwork.h> #include <IVehicleNetworkHalMock.h> #include <VehicleNetworkProto.pb.h> #include "BinderUtil.h" #include "VehicleNetworkProtoUtil.h" namespace android { enum { ON_LIST_PROPERTIES = IBinder::FIRST_CALL_TRANSACTION, ON_PROPERTY_SET, ON_PROPERTY_GET, ON_SUBSCRIBE, ON_UNSUBSCRIBE, }; // ---------------------------------------------------------------------------- const char IVehicleNetworkHalMock::SERVICE_NAME[] = "com.android.car.vehiclenetwork.IVehicleNetworkHalMock"; // ---------------------------------------------------------------------------- class BpVehicleNetworkHalMock : public BpInterface<IVehicleNetworkHalMock> { public: BpVehicleNetworkHalMock(const sp<IBinder> & impl) : BpInterface<IVehicleNetworkHalMock>(impl) { } virtual sp<VehiclePropertiesHolder> onListProperties() { sp<VehiclePropertiesHolder> holder; Parcel data, reply; data.writeInterfaceToken(IVehicleNetworkHalMock::getInterfaceDescriptor()); status_t status = remote()->transact(ON_LIST_PROPERTIES, data, &reply); if (status == NO_ERROR) { reply.readExceptionCode(); // for compatibility with java if (reply.readInt32() == 0) { // no result return holder; } ReadableBlobHolder blob(new Parcel::ReadableBlob()); if (blob.blob == NULL) { ALOGE("listProperties, no memory"); return holder; } int32_t size = reply.readInt32(); status = reply.readBlob(size, blob.blob); if (status != NO_ERROR) { ALOGE("listProperties, cannot read blob %d", status); return holder; } //TODO make this more memory efficient std::unique_ptr<VehiclePropConfigs> configs(new VehiclePropConfigs()); if (configs.get() == NULL) { return holder; } if(!configs->ParseFromArray(blob.blob->data(), size)) { ALOGE("listProperties, cannot parse reply"); return holder; } holder = new VehiclePropertiesHolder(); ASSERT_OR_HANDLE_NO_MEMORY(holder.get(), return); status = VehicleNetworkProtoUtil::fromVehiclePropConfigs(*configs.get(), holder->getList()); if (status != NO_ERROR) { ALOGE("listProperties, cannot convert VehiclePropConfigs %d", status); return holder; } } return holder; } virtual status_t onPropertySet(const vehicle_prop_value_t& value) { Parcel data, reply; data.writeInterfaceToken(IVehicleNetworkHalMock::getInterfaceDescriptor()); status_t status = VehiclePropValueBinderUtil::writeToParcel(data, value); if (status != NO_ERROR) { return status; } status = remote()->transact(ON_PROPERTY_SET, data, &reply); return status; } virtual status_t onPropertyGet(vehicle_prop_value_t* value) { if (value == NULL) { return BAD_VALUE; } Parcel data, reply; data.writeInterfaceToken(IVehicleNetworkHalMock::getInterfaceDescriptor()); status_t status = VehiclePropValueBinderUtil::writeToParcel(data, *value); if (status != NO_ERROR) { return status; } status = remote()->transact(ON_PROPERTY_GET, data, &reply); if (status == NO_ERROR) { reply.readExceptionCode(); // for compatibility with java status = VehiclePropValueBinderUtil::readFromParcel(reply, value); } return status; } virtual status_t onPropertySubscribe(int32_t property, float sampleRate, int32_t zones) { Parcel data, reply; data.writeInterfaceToken(IVehicleNetworkHalMock::getInterfaceDescriptor()); data.writeInt32(property); data.writeFloat(sampleRate); data.writeInt32(zones); status_t status = remote()->transact(ON_SUBSCRIBE, data, &reply); return status; } virtual void onPropertyUnsubscribe(int32_t property) { Parcel data, reply; data.writeInterfaceToken(IVehicleNetworkHalMock::getInterfaceDescriptor()); data.writeInt32(property); status_t status = remote()->transact(ON_UNSUBSCRIBE, data, &reply); if (status != NO_ERROR) { ALOGI("onPropertyUnsubscribe property %d failed %d", property, status); } } }; IMPLEMENT_META_INTERFACE(VehicleNetworkHalMock, IVehicleNetworkHalMock::SERVICE_NAME); // ---------------------------------------------------------------------- static bool isSystemUser() { uid_t uid = IPCThreadState::self()->getCallingUid(); switch (uid) { // This list will be expanded. Only those UIDs are allowed to access vehicle network // for now. There can be per property based UID check built-in as well. case AID_ROOT: case AID_SYSTEM: case AID_AUDIO: { return true; } break; default: { ALOGE("non-system user tried access, uid %d", uid); } break; } return false; } status_t BnVehicleNetworkHalMock::onTransact(uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) { if (!isSystemUser()) { return PERMISSION_DENIED; } status_t r; switch (code) { case ON_LIST_PROPERTIES: { CHECK_INTERFACE(IVehicleNetworkHalMock, data, reply); sp<VehiclePropertiesHolder> holder = onListProperties(); if (holder.get() == NULL) { // given property not found BinderUtil::fillObjectResultReply(reply, false /* isValid */); return NO_ERROR; } std::unique_ptr<VehiclePropConfigs> configs(new VehiclePropConfigs()); ASSERT_OR_HANDLE_NO_MEMORY(configs.get(), return NO_MEMORY); VehicleNetworkProtoUtil::toVehiclePropConfigs(holder->getList(), *configs.get()); int size = configs->ByteSize(); WritableBlobHolder blob(new Parcel::WritableBlob()); ASSERT_OR_HANDLE_NO_MEMORY(blob.blob, return NO_MEMORY); BinderUtil::fillObjectResultReply(reply, true); reply->writeInt32(size); reply->writeBlob(size, false, blob.blob); configs->SerializeToArray(blob.blob->data(), size); return NO_ERROR; } break; case ON_PROPERTY_SET: { CHECK_INTERFACE(IVehicleNetworkHalMock, data, reply); if (data.readInt32() == 0) { // java side allows passing null with this. return BAD_VALUE; } ScopedVehiclePropValue value; ReadableBlobHolder blob(new Parcel::ReadableBlob()); ASSERT_OR_HANDLE_NO_MEMORY(blob.blob, return NO_MEMORY); int32_t size = data.readInt32(); r = data.readBlob(size, blob.blob); if (r != NO_ERROR) { ALOGE("setProperty:service, cannot read blob"); return r; } std::unique_ptr<VehiclePropValue> v(new VehiclePropValue()); ASSERT_OR_HANDLE_NO_MEMORY(v.get(), return NO_MEMORY); if (!v->ParseFromArray(blob.blob->data(), size)) { ALOGE("setProperty:service, cannot parse data"); return BAD_VALUE; } r = VehicleNetworkProtoUtil::fromVehiclePropValue(*v.get(), value.value); if (r != NO_ERROR) { ALOGE("setProperty:service, cannot convert data"); return BAD_VALUE; } r = onPropertySet(value.value); BinderUtil::fillNoResultReply(reply); return r; } break; case ON_PROPERTY_GET: { CHECK_INTERFACE(IVehicleNetworkHalMock, data, reply); ScopedVehiclePropValue value; r = VehiclePropValueBinderUtil::readFromParcel(data, &value.value, false /* deleteMembers */, true /*canIgnoreNoData*/); if (r != NO_ERROR) { ALOGE("onPropertyGet cannot read %d", r); return r; } r = onPropertyGet(&(value.value)); if (r == NO_ERROR) { BinderUtil::fillObjectResultReply(reply, true); std::unique_ptr<VehiclePropValue> v(new VehiclePropValue()); ASSERT_OR_HANDLE_NO_MEMORY(v.get(), return NO_MEMORY); VehicleNetworkProtoUtil::toVehiclePropValue(value.value, *v.get()); int size = v->ByteSize(); WritableBlobHolder blob(new Parcel::WritableBlob()); ASSERT_OR_HANDLE_NO_MEMORY(blob.blob, return NO_MEMORY); reply->writeInt32(size); reply->writeBlob(size, false, blob.blob); v->SerializeToArray(blob.blob->data(), size); } return r; } break; case ON_SUBSCRIBE: { CHECK_INTERFACE(IVehicleNetworkHalMock, data, reply); int32_t property = data.readInt32(); float sampleRate = data.readFloat(); int32_t zones = data.readInt32(); r = onPropertySubscribe(property, sampleRate, zones); BinderUtil::fillNoResultReply(reply); return r; } break; case ON_UNSUBSCRIBE: { CHECK_INTERFACE(IVehicleNetworkHalMock, data, reply); int32_t property = data.readInt32(); onPropertyUnsubscribe(property); BinderUtil::fillNoResultReply(reply); return NO_ERROR; } break; default: return BBinder::onTransact(code, data, reply, flags); } } }; // namespace android