add error and hal restart monitoring with other cleanup
- add separate thread dispatch in native VehicleNetwork api.
- fix deadlock in binderDied: do not access HAL with lock held.
- fix missing sp in HandlerThread usage.
- add error listening and hal restart monitoring to binder callback.
- clarified mocking behavior:
clients listening for global error or HAL restart is not cleared by
mocking but client subscribing properties are all cleared and should
subscribe again.
- added native tests and Java tests to test mocking
bug: 24095928
(cherry picked from commit a116a2009ac8966b16cba1ab98d37ad8c537ab02)
Change-Id: I247c64dcb8722a678ed1c2e950a215a193a5e991
diff --git a/libvehiclenetwork/native/HandlerThread.cpp b/libvehiclenetwork/native/HandlerThread.cpp
new file mode 100644
index 0000000..2e15071
--- /dev/null
+++ b/libvehiclenetwork/native/HandlerThread.cpp
@@ -0,0 +1,72 @@
+/*
+ * 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.
+ */
+
+#include "HandlerThread.h"
+
+namespace android {
+
+HandlerThread::HandlerThread()
+ : mShouldQuit(false) {
+
+}
+
+HandlerThread::~HandlerThread() {
+ quit();
+}
+
+sp<Looper> HandlerThread::getLooper() {
+ Mutex::Autolock autoLock(mLock);
+ if (mLooper.get() == 0) {
+ mLooperWait.wait(mLock);
+ }
+ return mLooper;
+}
+
+status_t HandlerThread::start(const char* name, int32_t priority, size_t stack) {
+ return run(name, priority, stack);
+}
+
+void HandlerThread::quit() {
+ if (!isRunning()) {
+ return;
+ }
+ sp<Looper> looper = getLooper();
+ mLock.lock();
+ mShouldQuit = true;
+ mLock.unlock();
+ looper->wake();
+ requestExitAndWait();
+}
+
+bool HandlerThread::threadLoop() {
+ mLock.lock();
+ mLooper = Looper::prepare(0);
+ mLooperWait.broadcast();
+ mLock.unlock();
+ while (true) {
+ do {
+ Mutex::Autolock autoLock(mLock);
+ if (mShouldQuit) {
+ return false;
+ }
+ } while (false);
+ mLooper->pollOnce(-1);
+ }
+ return false;
+}
+
+
+};
diff --git a/libvehiclenetwork/native/IVehicleNetwork.cpp b/libvehiclenetwork/native/IVehicleNetwork.cpp
index 61fa208..0ceb1a0 100644
--- a/libvehiclenetwork/native/IVehicleNetwork.cpp
+++ b/libvehiclenetwork/native/IVehicleNetwork.cpp
@@ -40,6 +40,11 @@
INJECT_EVENT,
START_MOCKING,
STOP_MOCKING,
+ INJECT_HAL_ERROR,
+ START_ERROR_LISTENING,
+ STOP_ERROR_LISTENING,
+ START_HAL_RESTART_MONITORING,
+ STOP_HAL_RESTART_MONITORING
};
// ----------------------------------------------------------------------------
@@ -184,6 +189,52 @@
ALOGI("stop mocking failed %d", status);
}
}
+
+ status_t injectHalError(int32_t errorCode, int32_t property, int32_t operation) {
+ Parcel data, reply;
+ data.writeInterfaceToken(IVehicleNetwork::getInterfaceDescriptor());
+ data.writeInt32(errorCode);
+ data.writeInt32(property);
+ data.writeInt32(operation);
+ status_t status = remote()->transact(INJECT_HAL_ERROR, data, &reply);
+ return status;
+ }
+
+ virtual status_t startErrorListening(const sp<IVehicleNetworkListener> &listener) {
+ Parcel data, reply;
+ data.writeInterfaceToken(IVehicleNetwork::getInterfaceDescriptor());
+ data.writeStrongBinder(IInterface::asBinder(listener));
+ status_t status = remote()->transact(START_ERROR_LISTENING, data, &reply);
+ return status;
+ }
+
+ virtual void stopErrorListening(const sp<IVehicleNetworkListener> &listener) {
+ Parcel data, reply;
+ data.writeInterfaceToken(IVehicleNetwork::getInterfaceDescriptor());
+ data.writeStrongBinder(IInterface::asBinder(listener));
+ status_t status = remote()->transact(STOP_ERROR_LISTENING, data, &reply);
+ if (status != NO_ERROR) {
+ ALOGI("stopErrorListening %d", status);
+ }
+ }
+
+ virtual status_t startHalRestartMonitoring(const sp<IVehicleNetworkListener> &listener) {
+ Parcel data, reply;
+ data.writeInterfaceToken(IVehicleNetwork::getInterfaceDescriptor());
+ data.writeStrongBinder(IInterface::asBinder(listener));
+ status_t status = remote()->transact(START_HAL_RESTART_MONITORING, data, &reply);
+ return status;
+ }
+
+ virtual void stopHalRestartMonitoring(const sp<IVehicleNetworkListener> &listener) {
+ Parcel data, reply;
+ data.writeInterfaceToken(IVehicleNetwork::getInterfaceDescriptor());
+ data.writeStrongBinder(IInterface::asBinder(listener));
+ status_t status = remote()->transact(STOP_HAL_RESTART_MONITORING, data, &reply);
+ if (status != NO_ERROR) {
+ ALOGI("stopHalRestartMonitoring %d", status);
+ }
+ }
};
IMPLEMENT_META_INTERFACE(VehicleNetwork, IVehicleNetwork::SERVICE_NAME);
@@ -326,6 +377,47 @@
BinderUtil::fillNoResultReply(reply);
return NO_ERROR;
} break;
+ case INJECT_HAL_ERROR: {
+ CHECK_INTERFACE(IVehicleNetwork, data, reply);
+ int32_t errorCode = data.readInt32();
+ int32_t property = data.readInt32();
+ int32_t operation = data.readInt32();
+ r = injectHalError(errorCode, property, operation);
+ BinderUtil::fillNoResultReply(reply);
+ return r;
+ } break;
+ case START_ERROR_LISTENING: {
+ CHECK_INTERFACE(IVehicleNetwork, data, reply);
+ sp<IVehicleNetworkListener> listener =
+ interface_cast<IVehicleNetworkListener>(data.readStrongBinder());
+ r = startErrorListening(listener);
+ BinderUtil::fillNoResultReply(reply);
+ return r;
+ } break;
+ case STOP_ERROR_LISTENING: {
+ CHECK_INTERFACE(IVehicleNetwork, data, reply);
+ sp<IVehicleNetworkListener> listener =
+ interface_cast<IVehicleNetworkListener>(data.readStrongBinder());
+ stopErrorListening(listener);
+ BinderUtil::fillNoResultReply(reply);
+ return NO_ERROR;
+ } break;
+ case START_HAL_RESTART_MONITORING: {
+ CHECK_INTERFACE(IVehicleNetwork, data, reply);
+ sp<IVehicleNetworkListener> listener =
+ interface_cast<IVehicleNetworkListener>(data.readStrongBinder());
+ r = startHalRestartMonitoring(listener);
+ BinderUtil::fillNoResultReply(reply);
+ return r;
+ } break;
+ case STOP_HAL_RESTART_MONITORING: {
+ CHECK_INTERFACE(IVehicleNetwork, data, reply);
+ sp<IVehicleNetworkListener> listener =
+ interface_cast<IVehicleNetworkListener>(data.readStrongBinder());
+ stopHalRestartMonitoring(listener);
+ BinderUtil::fillNoResultReply(reply);
+ return NO_ERROR;
+ } break;
default:
return BBinder::onTransact(code, data, reply, flags);
}
diff --git a/libvehiclenetwork/native/IVehicleNetworkListener.cpp b/libvehiclenetwork/native/IVehicleNetworkListener.cpp
index e83a10c..b8579dc 100644
--- a/libvehiclenetwork/native/IVehicleNetworkListener.cpp
+++ b/libvehiclenetwork/native/IVehicleNetworkListener.cpp
@@ -33,6 +33,8 @@
enum {
ON_EVENTS = IBinder::FIRST_CALL_TRANSACTION,
+ ON_HAL_ERROR,
+ ON_HAL_RESTART,
};
class BpVehicleNetworkListener : public BpInterface<IVehicleNetworkListener>
@@ -42,14 +44,15 @@
: BpInterface<IVehicleNetworkListener>(impl) {
}
- virtual status_t onEvents(sp<VehiclePropValueListHolder>& events) {
+ virtual void onEvents(sp<VehiclePropValueListHolder>& events) {
Parcel data, reply;
data.writeInterfaceToken(IVehicleNetworkListener::getInterfaceDescriptor());
std::unique_ptr<VehiclePropValues> values(new VehiclePropValues());
ASSERT_OR_HANDLE_NO_MEMORY(values.get(), return NO_MEMORY);
status_t r = VehicleNetworkProtoUtil::toVehiclePropValues(events->getList(), *values.get());
if (r != NO_ERROR) {
- return r;
+ ALOGE("onEvents: toVehiclePropValues failed %d", r);
+ return;
}
data.writeInt32(1); // for java compatibility
WritableBlobHolder blob(new Parcel::WritableBlob());
@@ -57,8 +60,23 @@
data.writeInt32(size);
data.writeBlob(size, false, blob.blob);
values->SerializeToArray(blob.blob->data(), size);
- r = remote()->transact(ON_EVENTS, data, &reply);
- return r;
+ remote()->transact(ON_EVENTS, data, &reply);
+ }
+
+ virtual void onHalError(int32_t errorCode, int32_t property, int32_t operation) {
+ Parcel data, reply;
+ data.writeInterfaceToken(IVehicleNetworkListener::getInterfaceDescriptor());
+ data.writeInt32(errorCode);
+ data.writeInt32(property);
+ data.writeInt32(operation);
+ remote()->transact(ON_HAL_ERROR, data, &reply);
+ }
+
+ virtual void onHalRestart(bool inMocking) {
+ Parcel data, reply;
+ data.writeInterfaceToken(IVehicleNetworkListener::getInterfaceDescriptor());
+ data.writeInt32(inMocking ? 1 : 0);
+ remote()->transact(ON_HAL_RESTART, data, &reply);
}
};
@@ -98,8 +116,22 @@
ALOGE("onEvents: cannot convert data");
return BAD_VALUE;
}
- r = onEvents(holder);
- return r;
+ onEvents(holder);
+ return NO_ERROR;
+ } break;
+ case ON_HAL_ERROR: {
+ CHECK_INTERFACE(IVehicleNetworkListener, data, reply);
+ int32_t errorCode = data.readInt32();
+ int32_t property = data.readInt32();
+ int32_t operation = data.readInt32();
+ onHalError(errorCode, property, operation);
+ return NO_ERROR;
+ } break;
+ case ON_HAL_RESTART: {
+ CHECK_INTERFACE(IVehicleNetworkListener, data, reply);
+ bool inMocking = (data.readInt32() == 1);
+ onHalRestart(inMocking);
+ return NO_ERROR;
} break;
default:
return BBinder::onTransact(code, data, reply, flags);
diff --git a/libvehiclenetwork/native/VehicleNetwork.cpp b/libvehiclenetwork/native/VehicleNetwork.cpp
index 044d516..c68190e 100644
--- a/libvehiclenetwork/native/VehicleNetwork.cpp
+++ b/libvehiclenetwork/native/VehicleNetwork.cpp
@@ -13,6 +13,7 @@
* 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>
@@ -24,6 +25,111 @@
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));
@@ -32,7 +138,6 @@
sp<IVehicleNetwork> ivn(interface_cast<IVehicleNetwork>(binder));
vn = new VehicleNetwork(ivn, listener);
if (vn != NULL) {
- binder->linkToDeath(vn);
// in case thread pool is not started, start it.
ProcessState::self()->startThreadPool();
}
@@ -48,6 +153,21 @@
VehicleNetwork::~VehicleNetwork() {
IInterface::asBinder(mService)->unlinkToDeath(this);
+ mHandlerThread->quit();
+}
+
+void VehicleNetwork::onFirstRef() {
+ 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);
}
status_t VehicleNetwork::setInt32Property(int32_t property, int32_t value) {
@@ -144,14 +264,47 @@
mService->unsubscribe(this, property);
}
+status_t VehicleNetwork::injectEvent(const vehicle_prop_value_t& value) {
+ return mService->injectEvent(value);
+}
+
+status_t VehicleNetwork::startMocking(const sp<IVehicleNetworkHalMock>& mock) {
+ return mService->startMocking(mock);
+}
+
+void VehicleNetwork::stopMocking(const sp<IVehicleNetworkHalMock>& mock) {
+ mService->stopMocking(mock);
+}
+
+status_t VehicleNetwork::startErrorListening() {
+ return mService->startErrorListening(this);
+}
+
+void VehicleNetwork::stopErrorListening() {
+ mService->stopErrorListening(this);
+}
+
+status_t VehicleNetwork::startHalRestartMonitoring() {
+ return mService->startHalRestartMonitoring(this);
+}
+
+void VehicleNetwork::stopHalRestartMonitoring() {
+ mService->stopHalRestartMonitoring(this);
+}
+
void VehicleNetwork::binderDied(const wp<IBinder>& who) {
- //TODO
+ //TODO recover or notify and give up?
}
-status_t VehicleNetwork::onEvents(sp<VehiclePropValueListHolder>& events) {
- //TODO call this in separate thread to prevent blocking VNS
- mClientListener->onEvents(events);
- return NO_ERROR;
+void VehicleNetwork::onEvents(sp<VehiclePropValueListHolder>& events) {
+ mEventHandler->handleHalEvents(events);
}
+void VehicleNetwork::onHalError(int32_t errorCode, int32_t property, int32_t operation) {
+ mEventHandler->handleHalError(errorCode, property, operation);
+}
+
+void VehicleNetwork::onHalRestart(bool inMocking) {
+ mEventHandler->handleHalRestart(inMocking);
+}
}; // namespace android