/*
* 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 <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();
}
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::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::handleMessage(const Message& message) {
switch (message.what) {
case EVENT_EVENTS:
doHandleHalEvents();
break;
case EVENT_HAL_ERROR:
doHandleHalError();
break;
case EVENT_HAL_RESTART:
doHandleHalRestart();
break;
}
}
// ----------------------------------------------------------------------------
sp<VehicleNetwork> VehicleNetwork::createVehicleNetwork(sp<VehicleNetworkListener>& listener) {
sp<IBinder> binder = defaultServiceManager()->getService(
String16(IVehicleNetwork::SERVICE_NAME));
sp<VehicleNetwork> vn;
if (binder != NULL) {
sp<IVehicleNetwork> ivn(interface_cast<IVehicleNetwork>(binder));
vn = new VehicleNetwork(ivn, listener);
if (vn != NULL) {
// 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) {
return getService()->subscribe(this, property, sampleRate, zones);
}
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);
}
}; // namespace android