| /* |
| * 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.Lib" |
| |
| #include <assert.h> |
| #include <binder/IServiceManager.h> |
| #include <binder/ProcessState.h> |
| #include <utils/threads.h> |
| |
| #include <hardware/vehicle.h> |
| |
| #include <VehicleNetwork.h> |
| |
| namespace android { |
| |
| VehicleNetworkEventMessageHandler::VehicleNetworkEventMessageHandler(const sp<Looper>& looper, |
| sp<VehicleNetworkListener>& listener) : |
| mLooper(looper), |
| mListener(listener) { |
| |
| } |
| |
| VehicleNetworkEventMessageHandler::~VehicleNetworkEventMessageHandler() { |
| Mutex::Autolock autoLock(mLock); |
| mEvents.clear(); |
| for (VehicleHalError* e : mHalErrors) { |
| delete e; |
| } |
| mHalErrors.clear(); |
| mHalRestartEvents.clear(); |
| mSetValueEvents.clear(); |
| } |
| |
| void VehicleNetworkEventMessageHandler::handleHalEvents(sp<VehiclePropValueListHolder>& events) { |
| Mutex::Autolock autoLock(mLock); |
| mEvents.push_back(events); |
| mLooper->sendMessage(this, Message(EVENT_EVENTS)); |
| } |
| |
| void VehicleNetworkEventMessageHandler::handleHalError(int32_t errorCode, int32_t property, |
| int32_t operation) { |
| Mutex::Autolock autoLock(mLock); |
| VehicleHalError* error = new VehicleHalError(errorCode, property, operation); |
| if (error == NULL) { |
| ALOGE("VehicleNetworkEventMessageHandler::handleHalError, new failed"); |
| return; |
| } |
| mHalErrors.push_back(error); |
| mLooper->sendMessage(this, Message(EVENT_HAL_ERROR)); |
| } |
| |
| void VehicleNetworkEventMessageHandler::handleHalRestart(bool inMocking) { |
| Mutex::Autolock autoLock(mLock); |
| mHalRestartEvents.push_back(inMocking); |
| mLooper->sendMessage(this, Message(EVENT_HAL_RESTART)); |
| } |
| |
| void VehicleNetworkEventMessageHandler::handleOnPropertySet(const vehicle_prop_value_t& value) { |
| Mutex::Autolock autoLock(mLock); |
| mSetValueEvents.push_back(VehiclePropValueUtil::allocVehiclePropValue(value)); |
| mLooper->sendMessage(this, Message(EVENT_ON_SET)); |
| } |
| |
| void VehicleNetworkEventMessageHandler::doHandleHalEvents() { |
| sp<VehiclePropValueListHolder> values; |
| do { |
| Mutex::Autolock autoLock(mLock); |
| if (mEvents.size() > 0) { |
| auto itr = mEvents.begin(); |
| values = *itr; |
| mEvents.erase(itr); |
| } |
| } while (false); |
| if (values.get() != NULL) { |
| mListener->onEvents(values); |
| } |
| } |
| |
| void VehicleNetworkEventMessageHandler::doHandleHalError() { |
| VehicleHalError* error = NULL; |
| do { |
| Mutex::Autolock autoLock(mLock); |
| if (mHalErrors.size() > 0) { |
| auto itr = mHalErrors.begin(); |
| error = *itr; |
| mHalErrors.erase(itr); |
| } |
| } while (false); |
| if (error != NULL) { |
| mListener->onHalError(error->errorCode, error->property, error->operation); |
| delete error; |
| } |
| } |
| |
| void VehicleNetworkEventMessageHandler::doHandleHalRestart() { |
| bool shouldDispatch = false; |
| bool inMocking = false; |
| do { |
| Mutex::Autolock autoLock(mLock); |
| if (mHalRestartEvents.size() > 0) { |
| auto itr = mHalRestartEvents.begin(); |
| inMocking = *itr; |
| mHalRestartEvents.erase(itr); |
| shouldDispatch = true; |
| } |
| } while (false); |
| if (shouldDispatch) { |
| mListener->onHalRestart(inMocking); |
| } |
| } |
| |
| void VehicleNetworkEventMessageHandler::doHandleOnPropertySet() { |
| vehicle_prop_value_t* value = nullptr; |
| { |
| Mutex::Autolock autoLock(mLock); |
| if (!mSetValueEvents.empty()) { |
| auto itr = mSetValueEvents.begin(); |
| value = *itr; |
| mSetValueEvents.erase(itr); |
| } |
| } |
| if (value != nullptr) { |
| mListener->onPropertySet(*value); |
| VehiclePropValueUtil::deleteMembers(value); |
| delete value; |
| } |
| } |
| |
| void VehicleNetworkEventMessageHandler::handleMessage(const Message& message) { |
| switch (message.what) { |
| case EVENT_EVENTS: |
| doHandleHalEvents(); |
| break; |
| case EVENT_HAL_ERROR: |
| doHandleHalError(); |
| break; |
| case EVENT_HAL_RESTART: |
| doHandleHalRestart(); |
| break; |
| case EVENT_ON_SET: |
| doHandleOnPropertySet(); |
| break; |
| } |
| } |
| |
| // ---------------------------------------------------------------------------- |
| |
| static const int MAX_SERVICE_RETRY = 4; |
| |
| sp<VehicleNetwork> VehicleNetwork::createVehicleNetwork(sp<VehicleNetworkListener>& listener) { |
| sp<IBinder> binder; |
| int retry = 0; |
| while (true) { |
| binder = defaultServiceManager()->getService(String16(IVehicleNetwork::SERVICE_NAME)); |
| if (binder.get() != NULL) { |
| break; |
| } |
| retry++; |
| if (retry > MAX_SERVICE_RETRY) { |
| ALOGE("cannot get VNS, will crash"); |
| break; |
| } |
| } |
| ASSERT_ALWAYS_ON_NO_MEMORY(binder.get()); |
| sp<IVehicleNetwork> ivn(interface_cast<IVehicleNetwork>(binder)); |
| sp<VehicleNetwork> vn; |
| vn = new VehicleNetwork(ivn, listener); |
| ASSERT_ALWAYS_ON_NO_MEMORY(vn.get()); |
| // in case thread pool is not started, start it. |
| ProcessState::self()->startThreadPool(); |
| return vn; |
| } |
| |
| VehicleNetwork::VehicleNetwork(sp<IVehicleNetwork>& vehicleNetwork, |
| sp<VehicleNetworkListener> &listener) : |
| mService(vehicleNetwork), |
| mClientListener(listener) { |
| } |
| |
| VehicleNetwork::~VehicleNetwork() { |
| sp<IVehicleNetwork> service = getService(); |
| IInterface::asBinder(service)->unlinkToDeath(this); |
| service->stopHalRestartMonitoring(this); |
| mHandlerThread->quit(); |
| } |
| |
| void VehicleNetwork::onFirstRef() { |
| Mutex::Autolock autoLock(mLock); |
| mHandlerThread = new HandlerThread(); |
| status_t r = mHandlerThread->start("VNS.NATIVE_LOOP"); |
| if (r != NO_ERROR) { |
| ALOGE("cannot start handler thread, error:%d", r); |
| return; |
| } |
| sp<VehicleNetworkEventMessageHandler> handler( |
| new VehicleNetworkEventMessageHandler(mHandlerThread->getLooper(), mClientListener)); |
| ASSERT_ALWAYS_ON_NO_MEMORY(handler.get()); |
| mEventHandler = handler; |
| IInterface::asBinder(mService)->linkToDeath(this); |
| mService->startHalRestartMonitoring(this); |
| } |
| |
| status_t VehicleNetwork::setInt32Property(int32_t property, int32_t value) { |
| vehicle_prop_value_t v; |
| v.prop = property; |
| v.value_type = VEHICLE_VALUE_TYPE_INT32; |
| v.value.int32_value = value; |
| return setProperty(v); |
| } |
| |
| status_t VehicleNetwork::getInt32Property(int32_t property, int32_t* value, int64_t* timestamp) { |
| vehicle_prop_value_t v; |
| v.prop = property; |
| // do not check error as it is always safe to access members for this data type. |
| // saves one if for normal flow. |
| status_t r = getProperty(&v); |
| *value = v.value.int32_value; |
| *timestamp = v.timestamp; |
| return r; |
| } |
| |
| status_t VehicleNetwork::setInt64Property(int32_t property, int64_t value) { |
| vehicle_prop_value_t v; |
| v.prop = property; |
| v.value_type = VEHICLE_VALUE_TYPE_INT64; |
| v.value.int64_value = value; |
| return setProperty(v); |
| } |
| |
| status_t VehicleNetwork::getInt64Property(int32_t property, int64_t* value, int64_t* timestamp) { |
| vehicle_prop_value_t v; |
| v.prop = property; |
| status_t r = getProperty(&v); |
| *value = v.value.int64_value; |
| *timestamp = v.timestamp; |
| return r; |
| } |
| |
| status_t VehicleNetwork::setFloatProperty(int32_t property, float value) { |
| vehicle_prop_value_t v; |
| v.prop = property; |
| v.value_type = VEHICLE_VALUE_TYPE_FLOAT; |
| v.value.float_value = value; |
| return setProperty(v); |
| } |
| |
| status_t VehicleNetwork::getFloatProperty(int32_t property, float* value, int64_t* timestamp) { |
| vehicle_prop_value_t v; |
| v.prop = property; |
| status_t r = getProperty(&v); |
| *value = v.value.float_value; |
| *timestamp = v.timestamp; |
| return r; |
| } |
| |
| status_t VehicleNetwork::setStringProperty(int32_t property, const String8& value) { |
| vehicle_prop_value_t v; |
| v.prop = property; |
| v.value_type = VEHICLE_VALUE_TYPE_STRING; |
| v.value.str_value.data = (uint8_t*)value.string(); |
| v.value.str_value.len = value.length(); |
| return setProperty(v); |
| } |
| |
| status_t VehicleNetwork::getStringProperty(int32_t property, String8& value, int64_t* timestamp) { |
| vehicle_prop_value_t v; |
| v.prop = property; |
| v.value.str_value.len = 0; |
| status_t r = getProperty(&v); |
| if (r == NO_ERROR) { |
| value.setTo((char*)v.value.str_value.data, v.value.str_value.len); |
| } |
| *timestamp = v.timestamp; |
| return r; |
| } |
| |
| sp<VehiclePropertiesHolder> VehicleNetwork::listProperties(int32_t property) { |
| return getService()->listProperties(property); |
| } |
| |
| status_t VehicleNetwork::setProperty(const vehicle_prop_value_t& value) { |
| return getService()->setProperty(value); |
| } |
| |
| status_t VehicleNetwork::getProperty(vehicle_prop_value_t* value) { |
| return getService()->getProperty(value); |
| } |
| |
| status_t VehicleNetwork::subscribe(int32_t property, float sampleRate, int32_t zones, |
| int32_t flags) { |
| return getService()->subscribe(this, property, sampleRate, zones, flags); |
| } |
| |
| void VehicleNetwork::unsubscribe(int32_t property) { |
| getService()->unsubscribe(this, property); |
| } |
| |
| status_t VehicleNetwork::injectEvent(const vehicle_prop_value_t& value) { |
| return getService()->injectEvent(value); |
| } |
| |
| status_t VehicleNetwork::startMocking(const sp<IVehicleNetworkHalMock>& mock) { |
| return getService()->startMocking(mock); |
| } |
| |
| void VehicleNetwork::stopMocking(const sp<IVehicleNetworkHalMock>& mock) { |
| getService()->stopMocking(mock); |
| } |
| |
| status_t VehicleNetwork::startErrorListening() { |
| return getService()->startErrorListening(this); |
| } |
| |
| void VehicleNetwork::stopErrorListening() { |
| getService()->stopErrorListening(this); |
| } |
| |
| void VehicleNetwork::binderDied(const wp<IBinder>& who) { |
| ALOGE("service died"); |
| do { |
| Mutex::Autolock autoLock(mLock); |
| sp<IBinder> ibinder = who.promote(); |
| ibinder->unlinkToDeath(this); |
| sp<IBinder> binder = defaultServiceManager()->getService( |
| String16(IVehicleNetwork::SERVICE_NAME)); |
| mService = interface_cast<IVehicleNetwork>(binder); |
| IInterface::asBinder(mService)->linkToDeath(this); |
| mService->startHalRestartMonitoring(this); |
| } while (false); |
| onHalRestart(false); |
| } |
| |
| sp<IVehicleNetwork> VehicleNetwork::getService() { |
| Mutex::Autolock autoLock(mLock); |
| return mService; |
| } |
| |
| sp<VehicleNetworkEventMessageHandler> VehicleNetwork::getEventHandler() { |
| Mutex::Autolock autoLock(mLock); |
| return mEventHandler; |
| } |
| |
| void VehicleNetwork::onEvents(sp<VehiclePropValueListHolder>& events) { |
| getEventHandler()->handleHalEvents(events); |
| } |
| |
| void VehicleNetwork::onHalError(int32_t errorCode, int32_t property, int32_t operation) { |
| getEventHandler()->handleHalError(errorCode, property, operation); |
| } |
| |
| void VehicleNetwork::onHalRestart(bool inMocking) { |
| getEventHandler()->handleHalRestart(inMocking); |
| } |
| |
| void VehicleNetwork::onPropertySet(const vehicle_prop_value_t& value) { |
| getEventHandler()->handleOnPropertySet(value); |
| } |
| }; // namespace android |